diff --git a/docs/CustomizingAzdParameters.md b/docs/CustomizingAzdParameters.md index b74a1b48..6abe3728 100644 --- a/docs/CustomizingAzdParameters.md +++ b/docs/CustomizingAzdParameters.md @@ -10,7 +10,8 @@ By default this template will use the environment name as the prefix to prevent | Name | Type | Default Value | Purpose | | -----------------------------| ------- | ------------------- | ---------------------------------------------------------------------------------------------------- | | `AZURE_ENV_NAME` | string | `azdtemp` | Used as a prefix for all resource names to ensure uniqueness across environments. | -| `AZURE_ENV_COSMOS_LOCATION` | string | `eastus2` | Location of the Cosmos DB instance. Choose from (allowed values: `swedencentral`, `australiaeast`). | +| `AZURE_ENV_COSMOS_LOCATION` | string | `Same as resource group location` | Primary location for the Cosmos DB instance. When enabling redundancy, verify the region supports zone redundancy. [Check supported regions](https://learn.microsoft.com/en-us/azure/reliability/regions-list). | +| `AZURE_ENV_COSMOS_SECONDARY_LOCATION` | string | `canadacentral` | Secondary failover location for Cosmos DB when enableRedundancy is true. [Check supported regions](https://learn.microsoft.com/en-us/azure/reliability/regions-list). | | `AZURE_ENV_MODEL_DEPLOYMENT_TYPE` | string | `GlobalStandard` | Change the Model Deployment Type (allowed values: Standard, GlobalStandard). | | `AZURE_ENV_MODEL_NAME` | string | `gpt-4o-mini` | Set the GPT model name (allowed values: `gpt-4o`). | | `AZURE_ENV_MODEL_VERSION` | string | `2025-01-01-preview` | Set the Azure OpenAI API version (allowed values: 2024-08-06). | diff --git a/docs/DeployWithLimitedQuota.md b/docs/DeployWithLimitedQuota.md new file mode 100644 index 00000000..08bc415b --- /dev/null +++ b/docs/DeployWithLimitedQuota.md @@ -0,0 +1,99 @@ +# Deploying with Limited OpenAI Quota + +This document provides guidance on deploying the Build Your Own Copilot Solution Accelerator when you have limited Azure OpenAI model quota available. + +## Overview + +By default, the solution requires: +- **GPT model**: 200,000 Tokens Per Minute (TPM) +- **Embedding model**: 80,000 TPM + +If your Azure OpenAI service has lower quota limits, you can modify the deployment to work with reduced capacity. + +## Prerequisites + +Before proceeding, ensure you have: +- Azure Developer CLI (azd) installed +- Access to your Azure OpenAI service quota settings +- Knowledge of your current TPM limits + +## Deployment Options + +You have two approaches to deploy with less quota: + +### Option 1: Remove Quota Validation + +Remove the metadata section (lines 73-81) from the [`infra/main.bicep`](../infra/main.bicep) file: + +```bicep +@metadata({ + azd: { + type: 'location' + usageName: [ + 'OpenAI.GlobalStandard.gpt-4o-mini,200' + 'OpenAI.GlobalStandard.text-embedding-ada-002,80' + ] + } +}) +``` + +### Option 2: Modify Quota Thresholds (Recommended) + +Update the values on lines 77-78 in [`infra/main.bicep`](../infra/main.bicep) to match your available quota: + +```bicep +@metadata({ + azd: { + type: 'location' + usageName: [ + 'OpenAI.GlobalStandard.gpt-4o-mini, 50' // Changed from 200 + 'OpenAI.GlobalStandard.text-embedding-ada-002, 50' // Changed from 80 + ] + } +}) +``` + +## Configuration Steps + +After modifying the Bicep file, configure your deployment capacity: + +```powershell +azd env set AZURE_ENV_MODEL_CAPACITY="50" +azd env set AZURE_ENV_EMBEDDING_MODEL_CAPACITY="50" +``` + +> **Note**: Adjust the values (50) to match your actual available quota. + +## Deploy the Solution + +Once configured, proceed with deployment: + +```powershell +azd up +``` + +## Performance Considerations + +โš ๏ธ **Important**: Using reduced TPM limits may impact application performance: + +For optimal performance, we recommend maintaining at least 200,000 TPM for GPT models when possible. + +## Additional Resources + +For more detailed information, refer to: + +- [Deployment Guide](DeploymentGuide.md) - Complete deployment instructions +- [Customizing azd Parameters](CustomizingAzdParameters.md) - Advanced configuration options +- [Check or update Quota](AzureGPTQuotaSettings.md) - Check or update quota from Azure Portal +- [Quota Check](QuotaCheck.md) - Script for checking Azure OpenAI quota limits + +## Why we need to do this? +- The solution uses built-in Azure Developer CLI (azd) quota validation to prevent deployment failures. Specifically, azd performs pre-deployment checks to ensure sufficient quota is available i.e. 200k TPM for gpt model and 80k TPM for embedding model. + +- These quota thresholds are hardcoded in the infrastructure file because azd's quota checking mechanism doesn't currently support parameterized values. If your Azure OpenAI service has quota below these thresholds, the deployment will fail during the validation phase rather than proceeding and failing later in the process. + +- By following the steps above, you can either: + 1. **Bypass quota validation entirely** by removing the metadata block + 2. **Lower the validation thresholds** to match your available quota (e.g., 50,000 TPM) + +- This ensures successful deployment while working within your quota constraints. \ No newline at end of file diff --git a/docs/DeploymentGuide.md b/docs/DeploymentGuide.md index c3701330..caf3d8e6 100644 --- a/docs/DeploymentGuide.md +++ b/docs/DeploymentGuide.md @@ -236,7 +236,8 @@ Once you've opened the project in [Codespaces](#github-codespaces), [Dev Contain 5. Once the deployment is complete, please follow the [Import Sample Data](#post-deployment-steps) instructions under **Post Deployment Steps** to load the sample data correctly. 6. Open the [Azure Portal](https://portal.azure.com/), go to the deployed resource group, find the App Service and get the app URL from `Default domain`. 7. Test the app locally with the sample question with any selected client: _Show latest asset value by asset type?_. For more sample questions you can test in the application, see [Sample Questions](SampleQuestions.md). -8. You can now delete the resources by running `azd down`, if you are done trying out the application. +8. You can now delete the resources by running `azd down`, if you are done trying out the application. + > **Note:** If you deployed with `enableRedundancy=true` and Log Analytics workspace replication is enabled, you must first disable replication before running `azd down`, else resource group delete will fail. Follow the steps in [Handling Log Analytics Workspace Deletion with Replication Enabled](./LogAnalyticsReplicationDisable.md), wait until replication returns `false`, then run `azd down`. ### Publishing Local Build Container to Azure Container Registry diff --git a/docs/LogAnalyticsReplicationDisable.md b/docs/LogAnalyticsReplicationDisable.md new file mode 100644 index 00000000..0772b97b --- /dev/null +++ b/docs/LogAnalyticsReplicationDisable.md @@ -0,0 +1,28 @@ +# ๐Ÿ›  Handling Log Analytics Workspace Deletion with Replication Enabled + +If redundancy (replication) is enabled for your Log Analytics workspace, you must disable it before deleting the workspace or resource group. Otherwise, deletion will fail. + +## โœ… Steps to Disable Replication Before Deletion +Run the following Azure CLI command. Note: This operation may take about 5 minutes to complete. + +```bash +az resource update --ids "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{logAnalyticsName}" --set properties.replication.enabled=false +``` + +Replace: +- `{subscriptionId}` โ†’ Your Azure subscription ID +- `{resourceGroupName}` โ†’ The name of your resource group +- `{logAnalyticsName}` โ†’ The name of your Log Analytics workspace + +Optional: Verify replication is disabled (should output `false`): +```bash +az resource show --ids "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{logAnalyticsName}" --query properties.replication.enabled -o tsv +``` + +## โœ… After Disabling Replication +You can safely delete: +- The Log Analytics workspace (manual) +- The resource group (manual), or +- All provisioned resources via `azd down` + +Return to: [Deployment Guide](./DeploymentGuide.md) diff --git a/docs/TroubleShootingSteps.md b/docs/TroubleShootingSteps.md index 6ef58760..6a37f457 100644 --- a/docs/TroubleShootingSteps.md +++ b/docs/TroubleShootingSteps.md @@ -1,579 +1,157 @@ # ๐Ÿ› ๏ธ Troubleshooting - When deploying Azure resources, you may come across different error codes that stop or delay the deployment process. This section lists some of the most common errors along with possible causes and step-by-step resolutions. - -Use these as quick reference guides to unblock your deployments. - -## Error Codes - -
-ReadOnlyDisabledSubscription - -- Check if you have an active subscription before starting the deployment. - -
- -
- MissingSubscriptionRegistration/ AllowBringYourOwnPublicIpAddress/ InvalidAuthenticationToken - - -Enable `AllowBringYourOwnPublicIpAddress` Feature - -Before deploying the resources, you may need to enable the **Bring Your Own Public IP Address** feature in Azure. This is required only once per subscription. - -### Steps - -1. **Run the following command to register the feature:** - - ```bash - az feature register --namespace Microsoft.Network --name AllowBringYourOwnPublicIpAddress - ``` - -2. **Wait for the registration to complete.** - You can check the status using: - - ```bash - az feature show --namespace Microsoft.Network --name AllowBringYourOwnPublicIpAddress --query properties.state - ``` - -3. **The output should show:** - "Registered" - -4. **Once the feature is registered, refresh the provider:** - - ```bash - az provider register --namespace Microsoft.Network - ``` - - ๐Ÿ’ก Note: Feature registration may take several minutes to complete. This needs to be done only once per Azure subscription. - -
- -
-ResourceGroupNotFound - -## Option 1 -### Steps - -1. Go to [Azure Portal](https://portal.azure.com/#home). - -2. Click on the **"Resource groups"** option available on the Azure portal home page. -![alt text](../docs/images/AzureHomePage.png) - -3. In the Resource Groups search bar, search for the resource group you intend to target for deployment. If it exists, you can proceed with using it. -![alt text](../docs/images/resourcegroup1.png) - - ## Option 2 - -- This error can occur if you deploy the template using the same .env file - from a previous deployment. -- To avoid this issue, create a new environment before redeploying. -- You can use the following command to create a new environment: - ```bash - azd env new - ``` -
-
-ResourceGroupBeingDeleted - -To prevent this issue, please ensure that the resource group you are targeting for deployment is not currently being deleted. You can follow steps to verify resource group is being deleted or not. -### Steps: -1. Go to [Azure Portal](https://portal.azure.com/#home) -2. Go to resource group option and search for targeted resource group -3. If Targeted resource group is there and deletion for this is in progress, it means you cannot use this, you can create new or use any other resource group - -
- -
-InternalSubscriptionIsOverQuotaForSku/ManagedEnvironmentProvisioningError - -Quotas are applied per resource group, subscriptions, accounts, and other scopes. For example, your subscription might be configured to limit the number of vCPUs for a region. If you attempt to deploy a virtual machine with more vCPUs than the permitted amount, you receive an error that the quota was exceeded. -For PowerShell, use the `Get-AzVMUsage` cmdlet to find virtual machine quotas. -```ps -Get-AzVMUsage -Location "West US" -``` -based on available quota you can deploy application otherwise, you can request for more quota -
- -
-InsufficientQuota - -- Check if you have sufficient quota available in your subscription before deployment. -- To verify, refer to the [quota_check](../docs/QuotaCheck.md) file for details. - -
- -
-DeploymentModelNotSupported/ ServiceModelDeprecated/ InvalidResourceProperties - - - The updated model may not be supported in the selected region. Please verify its availability in the [Azure AI Foundry models](https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/models?tabs=global-standard%2Cstandard-chat-completions) document. - -
-
-LinkedInvalidPropertyId/ ResourceNotFound/DeploymentOutputEvaluationFailed/ CanNotRestoreANonExistingResource / The language expression property array index is out of bounds - -- Before using any resource ID, ensure it follows the correct format. -- Verify that the resource ID you are passing actually exists. -- Make sure there are no typos in the resource ID. -- Verify that the provisioning state of the existing resource is `Succeeded` by running the following command to avoid this error while deployment or restoring the resource. - - ```bash - az resource show --ids --query "properties.provisioningState" - ``` -- Sample Resource IDs format - - Log Analytics Workspace Resource ID - ``` - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{workspaceName} - ``` - - Azure AI Foundry Project Resource ID - ``` - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.MachineLearningServices/workspaces/{name} - ``` -- You may encounter the error `The language expression property array index '8' is out of bounds` if the resource ID is incomplete. Please ensure your resource ID is correct and contains all required information, as shown in sample resource IDs. - -- For more information refer [Resource Not Found errors solutions](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-not-found?tabs=bicep) - -
-
-ResourceNameInvalid - -- Ensure the resource name is within the allowed length and naming rules defined for that specific resource type, you can refer [Resource Naming Convention](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules) document. - -
-
-ServiceUnavailable/ResourceNotFound - - - Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/en-us/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions). - - - You can request more quota, refer [Quota Request](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/create-support-request-quota-increase) Documentation - - -
-
-Workspace Name - InvalidParameter - - To avoid this errors in workspace ID follow below rules. -1. Must start and end with an alphanumeric character (letter or number). -2. Allowed characters: - `aโ€“z` - `0โ€“9` - `- (hyphen)` -3. Cannot start or end with a hyphen -. -4. No spaces, underscores (_), periods (.), or special characters. -5. Must be unique within the Azure region & subscription. -6. Length: 3โ€“33 characters (for AML workspaces). -
-
-BadRequest: Dns record under zone Document is already taken - -This error can occur only when user hardcoding the CosmosDB Service name. To avoid this you can try few below suggestions. -- Verify resource names are globally unique. -- If you already created an account/resource with same name in another subscription or resource group, check and delete it before reusing the name. -- By default in this template we are using unique prefix with every resource/account name to avoid this kind for errors. -
-
-NetcfgSubnetRangeOutsideVnet - -- Ensure the subnetโ€™s IP address range falls within the virtual networkโ€™s address space. -- Always validate that the subnet CIDR block is a subset of the VNet range. -- For Azure Bastion, the AzureBastionSubnet must be at least /27. -- Confirm that the AzureBastionSubnet is deployed inside the VNet. -
-
-DisableExport_PublicNetworkAccessMustBeDisabled - -- Check container source: Confirm whether the deployment is using a Docker image or Azure Container Registry (ACR). -- Verify ACR configuration: If ACR is included, review its settings to ensure they comply with Azure requirements. -- Check export settings: If export is disabled in ACR, make sure public network access is also disabled. -- Dedeploy after fix: Correct the configuration and redeploy. This will prevent the Conflict error during deployment. -- For more information refer [ACR Data Loss Prevention](https://learn.microsoft.com/en-us/azure/container-registry/data-loss-prevention) document. -
-
-AccountProvisioningStateInvalid - -- The AccountProvisioningStateInvalid error occurs when you try to use resources while they are still in the Accepted provisioning state. -- This means the deployment has not yet fully completed. -- To avoid this error, wait until the provisioning state changes to Succeeded. -- Only use the resources once the deployment is fully completed. -
-
-VaultNameNotValid - - In this template Vault name will be unique everytime, but if you trying to hard code the name then please make sure below points. - 1. Check name length - - Ensure the Key Vault name is between 3 and 24 characters. - 2. Validate allowed characters - - The name can only contain letters (aโ€“z, Aโ€“Z) and numbers (0โ€“9). - - Hyphens are allowed, but not at the beginning or end, and not consecutive (--). -3. Ensure proper start and end - - The name must start with a letter. - - The name must end with a letter or digit (not a hyphen). -4. Test with a new name - - Example of a valid vault name: - โœ… `cartersaikeyvault1` - โœ… `securevaultdemo` - โœ… `kv-project123` -
-
-DeploymentCanceled - - There might be multiple reasons for this error you can follow below steps to troubleshoot. - 1. Check deployment history - - Go to Azure Portal โ†’ Resource Group โ†’ Deployments. - - Look at the detailed error message for the deployment that was canceled โ€” this will show which resource failed and why. - 2. Identify the root cause - - A DeploymentCanceled usually means: - - A dependent resource failed to deploy. - - A validation error occurred earlier. - - A manual cancellation was triggered. - - Expand the failed deployment logs for inner error messages. -3. Validate your template (ARM/Bicep) - Run: - ``` - az deployment group validate --resource-group --template-file main.bicep - ``` -4. Check resource limits/quotas - - Ensure you have not exceeded quotas (vCPUs, IPs, storage accounts, etc.), which can silently cause cancellation. -5. Fix the failed dependency - - If a specific resource shows BadRequest, Conflict, or ValidationError, resolve that first. - - Re-run the deployment after fixing the root cause. -6. Retry deployment - Once corrected, redeploy with: - ``` - az deployment group create --resource-group --template-file main.bicep - ``` -Essentially: DeploymentCanceled itself is just a wrapper error โ€” you need to check inner errors in the deployment logs to find the actual failure. -
-
-LocationNotAvailableForResourceType - -- You may encounter a LocationNotAvailableForResourceType error if you set the secondary location to 'Australia Central' in the main.bicep file. -- This happens because 'Australia Central' is not a supported region for that resource type. -- Always refer to the README file or Azure documentation to check the list of supported regions. -- Update the deployment with a valid supported region to resolve the issue. - -
- -
-InvalidResourceLocation - -- You may encounter an InvalidResourceLocation error if you change the region for Cosmos DB or the Storage Account (secondary location) multiple times in the main.bicep file and redeploy. -- Azure resources like Cosmos DB and Storage Accounts do not support changing regions after deployment. -- If you need to change the region again, first delete the existing deployment. -- Then redeploy the resources with the updated region configuration. - -
- -
- -DeploymentActive - -- This issue occurs when a deployment is already in progress and another deployment is triggered in the same resource group, causing a DeploymentActive error. -- Cancel the ongoing deployment before starting a new one. -- Do not initiate a new deployment in the same resource group until the previous one is completed. -
- -
-ResourceOperationFailure/ProvisioningDisabled - - - This error occurs when provisioning of a resource is restricted in the selected region. - It usually happens because the service is not available in that region or provisioning has been temporarily disabled. - - - Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/en-us/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions). - -- If you need to use the same region, you can request a quota or provisioning exception. - Refer [Quota Request](https://docs.microsoft.com/en-us/azure/sql-database/quota-increase-request) for more details. - -
- -
-MaxNumberOfRegionalEnvironmentsInSubExceeded - -- This error occurs when you try to create more than the allowed number of **Azure Container App Environments (ACA Environments)** in the same region for a subscription. -- For example, in **Sweden Central**, only **1 Container App Environment** is allowed per subscription. - -The subscription 'xxxx-xxxx' cannot have more than 1 Container App Environments in Sweden Central. - -- To fix this, you can: - - Deploy the Container App Environment in a **different region**, OR - - Request a quota increase via Azure Support โ†’ [Quota Increase Request](https://go.microsoft.com/fwlink/?linkid=2208872) - -
- -
-Unauthorized - Operation cannot be completed without additional quota - -- You can check your quota usage using `az vm list-usage`. - - ``` - az vm list-usage --location "" -o table - ``` -- To Request more quota refer [VM Quota Request](https://techcommunity.microsoft.com/blog/startupsatmicrosoftblog/how-to-increase-quota-for-specific-types-of-azure-virtual-machines/3792394). - -
- -
ParentResourceNotFound - - - -- You can refer to the [Parent Resource Not found](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-parent-resource?tabs=bicep) documentation if you encounter this error. - -
- -
ResourceProviderError - -- This error occurs when the resource provider is not registered in your subscription. -- To register it, refer to [Register Resource Provider](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/error-register-resource-provider?tabs=azure-cli) documentation. - -
-
Conflict - Cannot use the SKU Basic with File Change Audit for site. +When deploying Azure resources, you may come across different error codes that stop or delay the deployment process. This section lists some of the most common errors along with possible causes and step-by-step resolutions. -- This error happens because File Change Audit logs arenโ€™t supported on Basic SKU App Service Plans. - -- Upgrading to Premium/Isolated SKU (supports File Change Audit), or - -- Disabling File Change Audit in Diagnostic Settings if you must stay on Basic. -- Always cross-check the [supported log types](https://aka.ms/supported-log-types) - before adding diagnostic logs to your Bicep templates. - -
- -
- -AccountPropertyCannotBeUpdated - -- The property **`isHnsEnabled`** (Hierarchical Namespace for Data Lake Gen2) is **read-only** and can only be set during **storage account creation**. -- Once a storage account is created, this property **cannot be updated**. -- Trying to update it via ARM template, Bicep, CLI, or Portal will fail. - -- **Resolution** -- Create a **new storage account** with `isHnsEnabled=true` if you require hierarchical namespace. -- Migration may be needed if you already have data. -- Refer to [Storage Account Update Restrictions](https://aka.ms/storageaccountupdate) for more details. - -
- -
InvalidRequestContent - -- The deployment values either include values that aren't recognized, or required values are missing. Confirm the values for your resource type. -- You can refer [Invalid Request Content error](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/common-deployment-errors#:~:text=InvalidRequestContent,Template%20reference) documentation. - -
- -
ReadOnlyDisabledSubscription - -- Depending on the type of the Azure Subscription, the expiration date might have been reached. - -- You have to activate the Azure Subscription before creating any Azure resource. -- You can refer [Reactivate a disabled Azure subscription](https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/subscription-disabled) Documentation. - -
- - -
SkuNotAvailable - -- You receive this error in the following scenarios: - - When the resource SKU you've selected, such as VM size, isn't available for a location or zone. - - If you're deploying an Azure Spot VM or Spot scale set instance, and there isn't any capacity for Azure Spot in this location. For more information, see Spot error messages. -
- -
CrossTenantDeploymentNotPermitted - -- Check tenant match: Ensure your deployment identity (user/SP) and the target resource group are in the same tenant. - ``` - az account show - az group show --name - ``` - -- Verify pipeline/service principal: If using CI/CD, confirm the service principal belongs to the same tenant and has permissions on the resource group. - -- Avoid cross-tenant references: Make sure your Bicep doesnโ€™t reference subscriptions, resource groups, or resources in another tenant. - -- Test minimal deployment: Deploy a simple resource to the same resource group to confirm identity and tenant are correct. - -- Guest/external accounts: Avoid using guest users from other tenants; use native accounts or SPs in the tenant. - -
- -
RequestDisallowedByPolicy - -- This typically indicates that an Azure Policy is preventing the requested action due to policy restrictions in your subscription. - -- For more details and guidance on resolving this issue, please refer to the official Microsoft documentation: [RequestDisallowedByPolicy](https://learn.microsoft.com/en-us/troubleshoot/azure/azure-kubernetes/create-upgrade-delete/error-code-requestdisallowedbypolicy) - -
- -
-FlagMustBeSetForRestore/NameUnavailable/CustomDomainInUse - -- This error occurs when you try to deploy a Cognitive Services resource that was **soft-deleted** earlier. -- Azure requires you to explicitly set the **`restore` flag** to `true` if you want to recover the soft-deleted resource. -- If you donโ€™t want to restore the resource, you must **purge the deleted resource** first before redeploying. -Example causes: -- Trying to redeploy a Cognitive Services account with the same name as a previously deleted one. -- The deleted resource still exists in a **soft-delete retention state**. -**How to fix:** -1. If you want to restore โ†’ add `"restore": true` in your template properties. -2. If you want a fresh deployment โ†’ purge the resource using: - ```bash - az cognitiveservices account purge \ - --name \ - --resource-group \ - --location - ``` -For more details, refer to [Soft delete and resource restore](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/delete-resource-group?tabs=azure-powershell). -
- -
-PrincipalNotFound - -- This error occurs when the **principal ID** (Service Principal, User, or Group) specified in a role assignment or deployment does not exist in the Azure Active Directory tenant. -- It can also happen due to **replication delays** right after creating a new principal. -**Example causes:** -- The specified **Object ID** is invalid or belongs to another tenant. -- The principal was recently created but Azure AD has not yet replicated it. -- Attempting to assign a role to a non-existing or deleted Service Principal/User/Group. -**How to fix:** -1. Verify that the **principal ID is correct** and exists in the same directory/tenant. - ```bash - az ad sp show --id - ``` -2. If the principal was just created, wait a few minutes and retry. -3. Explicitly set the principalType property (ServicePrincipal, User, or Group) in your ARM/Bicep template to avoid replication delays. -4. If the principal does not exist, create it again before assigning roles. -For more details, see [Azure PrincipalType documentation](https://learn.microsoft.com/en-us/azure/role-based-access-control/troubleshooting?tabs=bicep) -
-
-RedundancyConfigurationNotAvailableInRegion - -- This issue happens when you try to create a **Storage Account** with a redundancy configuration (e.g., `Standard_GRS`) that is **not supported in the selected Azure region**. -- Example: Creating a storage account with **GRS** in **italynorth** will fail with this error. -```bash -az storage account create -n mystorageacct123 -g myResourceGroup -l italynorth --sku Standard_GRS --kind StorageV2 -``` -- To check supported SKUs for your region: -```bash -az storage account list-skus -l italynorth -o table -``` -Use a supported redundancy option (e.g., Standard_LRS) in the same region -Or deploy the Storage Account in a region that supports your chosen redundancy. -For more details, refer to [Azure Storage redundancy documentation](https://learn.microsoft.com/en-us/azure/storage/common/storage-redundancy?utm_source=chatgpt.com). -
- -
DeploymentNotFound - -- This issue occurs when the user deletes a previous deployment along with the resource group (RG), and then redeploys the same RG with the same environment name but in a different location. - -- To avoid the DeploymentNotFound error, Do not change the location when redeploying a deleted RG, or Use new names for the RG and environment during redeployment. -
- -
DeploymentCanceled(user.canceled) - -- Indicates the deployment was manually canceled by the user (Portal, CLI, or pipeline). - -- Check deployment history and logs to confirm who/when it was canceled. - -- If accidental, retry the deployment. - -- For pipelines, ensure no automation or timeout is triggering cancellation. - -- Use deployment locks or retry logic to prevent accidental cancellations. - -
- -
ResourceGroupDeletionTimeout - -- Some resources in the resource group may be stuck deleting or have dependencies; check RG resources and status. - -- Ensure no resource locks or Azure Policies are blocking deletion. - -- Retry deletion via CLI/PowerShell `(az group delete --name --yes --no-wait)`. - -- Check Activity Log to identify failing resources; escalate to Azure Support if deletion is stuck. - -
- -
-SubscriptionDoesNotHaveServer - -- This issue happens when you try to reference an **Azure SQL Server** (`Microsoft.Sql/servers`) that does not exist in the selected subscription. -- It can occur if: - - The SQL server name is typed incorrectly. - - The SQL server was **deleted** but is still being referenced. - - You are working in the **wrong subscription context**. - - The server exists in a **different subscription/tenant** where you donโ€™t have access. - -**Reproduce:** -1. Run an Azure CLI command with a non-existent server name: -```bash - az sql db list --server sql-doesnotexist --resource-group myResourceGroup -``` - - or - -```bash - az sql server show --name sql-caqfrhxr4i3hyj --resource-group myResourceGroup - -``` - -Resolution: - -Verify the SQL Server name exists in your subscription: - -```bash - az sql server list --output table -``` -Make sure you are targeting the correct subscription: - -```bash - az account show - az account set --subscription -``` -If the server was deleted, either restore it (if possible) or update references to use a valid existing server. - -
- - -
BadRequest - DatabaseAccount is in a failed provisioning state because the previous attempt to create it was not successful - -- This error occurs when a user attempts to redeploy a resource that previously failed to provision. +Use these as quick reference guides to unblock your deployments. -- To resolve the issue, delete the failed deployment first, then start a new deployment. +## โšก Most Frequently Encountered Errors + +| Error Code | Common Cause | Full Details | +|------------|--------------|--------------| +| **InsufficientQuota** | Not enough quota available in subscription | [View Solution](#quota--capacity-limitations) | +| **MissingSubscriptionRegistration** | Required feature not registered in subscription | [View Solution](#subscription--access-issues) | +| **ResourceGroupNotFound** | RG doesn't exist or using old .env file | [View Solution](#resource-group--deployment-management) | +| **DeploymentModelNotSupported** | Model not available in selected region | [View Solution](#regional--location-issues) | +| **DeploymentNotFound** | Deployment record not found or was deleted | [View Solution](#resource-group--deployment-management) | +| **ResourceNotFound** | Resource does not exist or cannot be found | [View Solution](#resource-identification--references) | +| **SpecialFeatureOrQuotaIdRequired** | Subscription lacks access to specific model | [View Solution](#subscription--access-issues) | +| **ContainerAppOperationError** | Improperly built container image | [View Solution](#miscellaneous) | +| **ServiceUnavailable** | Service not available in selected region | [View Solution](#regional--location-issues) | +| **BadRequest - DatabaseAccount is in a failed provisioning state** | Previous deployment failed | [View Solution](#resource-state--provisioning) | +| **Unauthorized - Operation cannot be completed
without additional quota** | Insufficient quota for requested operation | [View Solution](#subscription--access-issues) | +| **ResourceGroupBeingDeleted** | Resource group deletion in progress | [View Solution](#resource-group--deployment-management) | +| **FlagMustBeSetForRestore** | Soft-deleted resource requires restore flag or purge | [View Solution](#miscellaneous) | +| **ParentResourceNotFound** | Parent resource does not exist or cannot be found | [View Solution](#resource-identification--references) | +| **AccountProvisioningStateInvalid** | Resource used before provisioning completed | [View Solution](#resource-state--provisioning) | +| **InternalSubscriptionIsOverQuotaForSku** | Subscription quota exceeded for the requested SKU | [View Solution](#quota--capacity-limitations) | +| **InvalidResourceGroup** | Invalid resource group configuration | [View Solution](#resource-group--deployment-management) | +| **RequestDisallowedByPolicy** | Azure Policy blocking the requested operation | [View Solution](#subscription--access-issues) | + +## ๐Ÿ“– Table of Contents + +- [Subscription & Access Issues](#subscription--access-issues) +- [Quota & Capacity Limitations](#quota--capacity-limitations) +- [Regional & Location Issues](#regional--location-issues) +- [Resource Naming & Validation](#resource-naming--validation) +- [Resource Identification & References](#resource-identification--references) +- [Network & Infrastructure Configuration](#network--infrastructure-configuration) +- [Configuration & Property Errors](#configuration--property-errors) +- [Resource State & Provisioning](#resource-state--provisioning) +- [Miscellaneous](#miscellaneous) + +## Subscription & Access Issues + +| Issue/Error Code | Description | Steps to Resolve | +|-----------|-------------|------------------| +| **ReadOnlyDisabledSubscription** | Subscription is disabled or in read-only state | | +| **MissingSubscriptionRegistration/
AllowBringYourOwnPublicIpAddress** | Required feature not registered in subscription | **Enable `AllowBringYourOwnPublicIpAddress` Feature**

Before deploying the resources, you may need to enable the **Bring Your Own Public IP Address** feature in Azure. This is required only once per subscription.

**Steps:**
๐Ÿ’ก Note: Feature registration may take several minutes to complete. This needs to be done only once per Azure subscription. | +| **Unauthorized - Operation cannot be completed without additional quota** | Insufficient quota for requested operation | | +| **CrossTenantDeploymentNotPermitted** | Deployment across different Azure AD tenants not allowed | | +| **RequestDisallowedByPolicy** | Azure Policy blocking the requested operation | | +| **SpecialFeatureOrQuotaIdRequired** | Subscription lacks access to specific Azure OpenAI models | This error occurs when your subscription does not have access to certain Azure OpenAI models.

**Example error message:**
`SpecialFeatureOrQuotaIdRequired: The current subscription does not have access to this model 'Format:OpenAI,Name:o3,Version:2025-04-16'.`

**Resolution:**
To gain access, submit a request using the official form:
๐Ÿ‘‰ [Azure OpenAI Model Access Request](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUQ1VGQUEzRlBIMVU2UFlHSFpSNkpOR0paRSQlQCN0PWcu)

You'll need to use this form if you require access to the following restricted models:
Once your request is approved, redeploy your resource. | +| **ResourceProviderError** | Resource provider not registered in subscription | | + +-------------------------------- + +## Quota & Capacity Limitations + +| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **InternalSubscriptionIsOverQuotaForSku/
ManagedEnvironmentProvisioningError** | Subscription quota exceeded for the requested SKU | Quotas are applied per resource group, subscriptions, accounts, and other scopes. For example, your subscription might be configured to limit the number of vCPUs for a region. If you attempt to deploy a virtual machine with more vCPUs than the permitted amount, you receive an error that the quota was exceeded.

For PowerShell, use the `Get-AzVMUsage` cmdlet to find virtual machine quotas:
`Get-AzVMUsage -Location "West US"`

Based on available quota you can deploy application otherwise, you can request for more quota | +| **InsufficientQuota** | Not enough quota available in subscription | | +| **MaxNumberOfRegionalEnvironmentsInSubExceeded** | Maximum Container App Environments limit reached for region |This error occurs when you attempt to create more **Azure Container App Environments** than the regional quota limit allows for your subscription. Each Azure region has a specific limit on the number of Container App Environments that can be created per subscription.

**Common Causes:**

**Resolution:**

**Reference:**
| +| **SkuNotAvailable** | Requested SKU not available in selected location or zone | You receive this error in the following scenarios:
| +| **Conflict - No available instances to satisfy this request** | Azure App Service has insufficient capacity in the region | This error occurs when Azure App Service doesn't have enough available compute instances in the selected region to provision or scale your app.

**Common Causes:**

**Resolution:**

**Reference:** [Azure App Service Plans](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans) | + +-------------------------------- + +## Resource Group & Deployment Management + +| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **ResourceGroupNotFound** | Specified resource group does not exist | **Option 1:**

**Option 2:**
| +| **ResourceGroupBeingDeleted** | Resource group is currently being deleted | **Steps:**
| +| **DeploymentActive** | Another deployment is already in progress in this resource group | | +| **DeploymentCanceled** | Deployment was canceled before completion |
๐Ÿ’ก **Note:** DeploymentCanceled is a wrapper error โ€” check inner errors in deployment logs | +| **DeploymentCanceled(user.canceled)** | User manually canceled the deployment | | +| **DeploymentNotFound** | Deployment record not found or was deleted | | +| **ResourceGroupDeletionTimeout** | Resource group deletion exceeded timeout limit | | + +-------------------------------- + +## Regional & Location Issues + +| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **LocationNotAvailableForResourceType** | Resource type not supported in selected region | This error occurs when you attempt to deploy a resource to a region that does not support that specific resource type or SKU.

**Resolution:**
| +| **InvalidResourceLocation** | Cannot change region for already deployed resources | This error occurs when you attempt to modify the location/region of a resource that has already been deployed. Azure resources **cannot change regions** after creation.

**Resolution:**

โš ๏ธ **Important:** Backup critical data before deleting resources.

**Reference:** [Move Azure resources across regions](https://learn.microsoft.com/en-us/azure/resource-mover/overview) | +| **ServiceUnavailable/ResourceNotFound** | Service unavailable or restricted in selected region | | +| **ResourceOperationFailure/
ProvisioningDisabled** | Resource provisioning restricted or disabled in region | | +| **RedundancyConfigurationNotAvailableInRegion** | Redundancy configuration not supported in selected region | | + +-------------------------------- + +## Resource Naming & Validation + +| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **ResourceNameInvalid** | Resource name violates naming convention rules | | +| **Workspace Name - InvalidParameter** | Workspace name does not meet required format | To avoid this errors in workspace ID follow below rules:
| +| **VaultNameNotValid** | Key Vault name does not meet naming requirements | In this template Vault name will be unique everytime, but if you trying to hard code the name then please make sure below points:
| +| **BadRequest: Dns record under zone Document is already taken** | DNS record name already in use | This error can occur only when user hardcoding the CosmosDB Service name. To avoid this you can try few below suggestions:
| + +--------------------------------- + +## Resource Identification & References + +| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **LinkedInvalidPropertyId/
ResourceNotFound/
DeploymentOutputEvaluationFailed/
CanNotRestoreANonExistingResource/
The language expression property array index is out of bounds** | Invalid or non-existent resource ID reference | | +| **ParentResourceNotFound** | Parent resource does not exist or cannot be found | | +| **PrincipalNotFound** | Principal ID does not exist in Azure AD tenant | This error occurs when the **principal ID** (Service Principal, User, or Group) specified in a role assignment or deployment does not exist in the Azure Active Directory tenant. It can also happen due to **replication delays** right after creating a new principal.

**Example causes:**

**How to fix:**
| +| **SubscriptionDoesNotHaveServer** | Referenced SQL Server does not exist in subscription | This issue happens when you try to reference an **Azure SQL Server** (`Microsoft.Sql/servers`) that does not exist in the selected subscription.

**It can occur if:**

**Reproduce:**
Run an Azure CLI command with a non-existent server name:
`az sql db list --server sql-doesnotexist --resource-group myResourceGroup`
or
`az sql server show --name sql-caqfrhxr4i3hyj --resource-group myResourceGroup`

**Resolution:**
| + +--------------------------------- + +## Network & Infrastructure Configuration + +| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **NetcfgSubnetRangeOutsideVnet** | Subnet IP range outside virtual network address space | | +| **DisableExport_PublicNetworkAccessMustBeDisabled** | Public network access must be disabled when export is disabled | | -- For guidance on deleting a resource from a Resource Group, refer to the following link: [Delete an Azure Cosmos DB account](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/manage-with-powershell#delete-account:~:text=%3A%24enableMultiMaster-,Delete%20an%20Azure%20Cosmos%20DB%20account,-This%20command%20deletes) +--------------------------------- -
+## Configuration & Property Errors -
+| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **InvalidRequestContent** | Deployment contains unrecognized or missing required values | | +| **Conflict - Cannot use the SKU Basic with File Change Audit for site** | File Change Audit not supported on Basic SKU | | +| **AccountPropertyCannotBeUpdated** | Read-only property cannot be modified after creation | The property **`isHnsEnabled`** (Hierarchical Namespace for Data Lake Gen2) is **read-only** and can only be set during **storage account creation**. Once a storage account is created, this property **cannot be updated**. Trying to update it via ARM template, Bicep, CLI, or Portal will fail.

**Resolution:**
| -SpecialFeatureOrQuotaIdRequired -This error occurs when your subscription does not have access to certain Azure OpenAI models. +---------------------------------- -**Example error message:** -`SpecialFeatureOrQuotaIdRequired: The current subscription does not have access to this model 'Format:OpenAI,Name:o3,Version:2025-04-16'.` +## Resource State & Provisioning -**Resolution:** -To gain access, submit a request using the official form: -๐Ÿ‘‰ [Azure OpenAI Model Access Request](https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUQ1VGQUEzRlBIMVU2UFlHSFpSNkpOR0paRSQlQCN0PWcu) +| Issue/Error Code | Description | Steps to Resolve | +|-----------------|-------------|------------------| +| **AccountProvisioningStateInvalid** | Resource used before provisioning completed | | +| **BadRequest - DatabaseAccount is in a failed provisioning state because the previous attempt to create it was not successful** | Database account failed to provision previously | | +| **ServiceDeleting** | Cannot provision service because deletion is still in progress | This error occurs when you attempt to create an Azure Search service with the same name as one that is currently being deleted. Azure Search services have a **soft-delete period** during which the service name remains reserved.

**Common causes:**

**Resolution:**
| -Youโ€™ll need to use this form if you require access to the following restricted models: -- gpt-5 -- o3 -- o3-pro -- deep research -- reasoning summary -- gpt-image-1 +--------------------------------- -Once your request is approved, redeploy your resource. +## Miscellaneous -
+| Issue/Error Code | Description | Steps to Resolve | +|-------------|-------------|------------------| +| **DeploymentModelNotSupported/
ServiceModelDeprecated/
InvalidResourceProperties** | Model not supported or deprecated in selected region | | +| **FlagMustBeSetForRestore/
NameUnavailable/
CustomDomainInUse** | Soft-deleted resource requires restore flag or purge | This error occurs when you try to deploy a Cognitive Services resource that was **soft-deleted** earlier. Azure requires you to explicitly set the **`restore` flag** to `true` if you want to recover the soft-deleted resource. If you don't want to restore the resource, you must **purge the deleted resource** first before redeploying.

**Example causes:**

**How to fix:**
| +| **ContainerAppOperationError** | Container image build or deployment issue | | -
-ContainerAppOperationError - -- The error is likely due to an improperly built container image. For resolution steps, refer to the [Azure Container Registry (ACR) โ€“ Build & Push Guide](./ACRBuildAndPushGuide.md) - -
+--------------------------------- ๐Ÿ’ก Note: If you encounter any other issues, you can refer to the [Common Deployment Errors](https://learn.microsoft.com/en-us/azure/azure-resource-manager/troubleshooting/common-deployment-errors) documentation. If the problem persists, you can also raise an bug in our [BYOC-Client Advisor Github Issues](https://github.com/microsoft/Build-your-own-copilot-Solution-Accelerator/issues) for further support. diff --git a/infra/main.bicep b/infra/main.bicep index 1acdaec7..be662958 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -10,7 +10,10 @@ param solutionName string = 'clientadvisor' param existingLogAnalyticsWorkspaceId string = '' @description('Optional. CosmosDB Location') -param cosmosLocation string = 'eastus2' +param cosmosLocation string = resourceGroup().location + +@description('Optional. Secondary CosmosDB Location for high availability and failover scenarios. Not all Azure regions support zone redundancy for Cosmos DB. See https://learn.microsoft.com/azure/cosmos-db/high-availability#azure-regions-and-zone-redundancy for supported regions.') +param secondaryCosmosLocation string = 'canadacentral' @minLength(1) @description('Optional. GPT model deployment type:') @@ -231,20 +234,6 @@ var replicaLocation = replicaRegionPairs[resourceGroup().location] @description('Optional. The tags to apply to all deployed Azure resources.') param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = {} -// Region pairs list based on article in [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions) for supported high availability regions for CosmosDB. -var cosmosDbZoneRedundantHaRegionPairs = { - australiaeast: 'uksouth' //'southeastasia' - centralus: 'eastus2' - eastasia: 'southeastasia' - eastus: 'centralus' - eastus2: 'centralus' - japaneast: 'australiaeast' - northeurope: 'westeurope' - southeastasia: 'eastasia' - uksouth: 'westeurope' - westeurope: 'northeurope' -} - var allTags = union( { 'azd-env-name': solutionName @@ -252,9 +241,6 @@ var allTags = union( tags ) -// Paired location calculated based on 'location' parameter. This location will be used by applicable resources if `enableScalability` is set to `true` -var cosmosDbHaLocation = cosmosDbZoneRedundantHaRegionPairs[resourceGroup().location] - // Extracts subscription, resource group, and workspace name from the resource ID when using an existing Log Analytics workspace var useExistingLogAnalytics = !empty(existingLogAnalyticsWorkspaceId) @@ -557,7 +543,7 @@ module keyvault 'br/public:avm/res/key-vault/vault:0.12.1' = { name: keyVaultName location: solutionLocation tags: tags - sku: 'standard' + sku: enableScalability ? 'premium' : 'standard' publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' networkAcls: { defaultAction: 'Allow' @@ -843,12 +829,12 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.15.0' = { { failoverPriority: 0 isZoneRedundant: true - locationName: solutionLocation + locationName: cosmosLocation } { failoverPriority: 1 isZoneRedundant: true - locationName: cosmosDbHaLocation + locationName: secondaryCosmosLocation } ] : [ @@ -1014,22 +1000,6 @@ module sqlDBModule 'br/public:avm/res/sql/server:0.20.1' = { ] } primaryUserAssignedIdentityResourceId: userAssignedIdentity.outputs.resourceId - privateEndpoints: enablePrivateNetworking - ? [ - { - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [ - { - privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.sqlServer]!.outputs.resourceId - } - ] - } - service: 'sqlServer' - subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId - tags: tags - } - ] - : [] firewallRules: (!enablePrivateNetworking) ? [ { endIpAddress: '255.255.255.255' @@ -1045,6 +1015,34 @@ module sqlDBModule 'br/public:avm/res/sql/server:0.20.1' = { tags: tags } } +// ========== SQL Server Private Endpoint (separated) ========== // +module sqlDbPrivateEndpoint 'br/public:avm/res/network/private-endpoint:0.11.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.private-endpoint.sql-${solutionSuffix}', 64) + params: { + name: 'pep-sql-${solutionSuffix}' + location: solutionLocation + tags: tags + enableTelemetry: enableTelemetry + subnetResourceId: virtualNetwork!.outputs.pepsSubnetResourceId + customNetworkInterfaceName: 'nic-sql-${solutionSuffix}' + privateLinkServiceConnections: [ + { + name: 'pl-sqlserver-${solutionSuffix}' + properties: { + privateLinkServiceId: sqlDBModule.outputs.resourceId + groupIds: ['sqlServer'] + } + } + ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.sqlServer]!.outputs.resourceId + } + ] + } + } +} // ========== Frontend server farm ========== // // WAF best practices for Web Application Services: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps @@ -1062,11 +1060,11 @@ module webServerFarm 'br/public:avm/res/web/serverfarm:0.5.0' = { // WAF aligned configuration for Monitoring diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null // WAF aligned configuration for Scalability - skuName: enableScalability || enableRedundancy ? 'P1v3' : 'B3' + skuName: 'B3' // skuCapacity: enableScalability ? 3 : 1 skuCapacity: 1 // skuCapacity set to 1 (not 3) due to multiple agents created per type during WAF deployment // WAF aligned configuration for Redundancy - zoneRedundant: enableRedundancy ? true : false + zoneRedundant: false // zone redundancy requires a minimum of 2 instances; as we are keeping skuCapacity to 1, setting zoneRedundant to false } } @@ -1218,7 +1216,7 @@ module searchService 'br/public:avm/res/search/search-service:0.11.1' = { ] partitionCount: 1 replicaCount: 1 - sku: 'standard' + sku: enableScalability ? 'standard' : 'basic' semanticSearch: 'free' // Use the deployment tags provided to the template tags: tags diff --git a/infra/main.json b/infra/main.json index 515dc388..d3ad6549 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "10200691163213391924" + "version": "0.39.26.7824", + "templateHash": "4551936874633515152" } }, "parameters": { @@ -28,11 +28,18 @@ }, "cosmosLocation": { "type": "string", - "defaultValue": "eastus2", + "defaultValue": "[resourceGroup().location]", "metadata": { "description": "Optional. CosmosDB Location" } }, + "secondaryCosmosLocation": { + "type": "string", + "defaultValue": "canadacentral", + "metadata": { + "description": "Optional. Secondary CosmosDB Location for high availability and failover scenarios. Not all Azure regions support zone redundancy for Cosmos DB. See https://learn.microsoft.com/azure/cosmos-db/high-availability#azure-regions-and-zone-redundancy for supported regions." + } + }, "gptModelDeploymentType": { "type": "string", "defaultValue": "GlobalStandard", @@ -307,20 +314,7 @@ "westeurope": "northeurope" }, "replicaLocation": "[variables('replicaRegionPairs')[resourceGroup().location]]", - "cosmosDbZoneRedundantHaRegionPairs": { - "australiaeast": "uksouth", - "centralus": "eastus2", - "eastasia": "southeastasia", - "eastus": "centralus", - "eastus2": "centralus", - "japaneast": "australiaeast", - "northeurope": "westeurope", - "southeastasia": "eastasia", - "uksouth": "westeurope", - "westeurope": "northeurope" - }, "allTags": "[union(createObject('azd-env-name', parameters('solutionName')), parameters('tags'))]", - "cosmosDbHaLocation": "[variables('cosmosDbZoneRedundantHaRegionPairs')[resourceGroup().location]]", "useExistingLogAnalytics": "[not(empty(parameters('existingLogAnalyticsWorkspaceId')))]", "logAnalyticsWorkspaceResourceName": "[format('log-{0}', variables('solutionSuffix'))]", "applicationInsightsResourceName": "[format('appi-{0}', variables('solutionSuffix'))]", @@ -456,7 +450,7 @@ "logAnalyticsWorkspace": { "condition": "[and(parameters('enableMonitoring'), not(variables('useExistingLogAnalytics')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -3562,7 +3556,7 @@ "applicationInsights": { "condition": "[parameters('enableMonitoring')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.insights.component.{0}', variables('applicationInsightsResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -4292,7 +4286,7 @@ }, "userAssignedIdentity": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('userAssignedIdentityResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -4774,7 +4768,7 @@ }, "sqlUserAssignedIdentity": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('sqlUserAssignedIdentityResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -5257,7 +5251,7 @@ "virtualNetwork": { "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('module.virtualNetwork.{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -5294,8 +5288,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "15908341678380884075" + "version": "0.39.26.7824", + "templateHash": "14641679443140532549" } }, "definitions": { @@ -5688,7 +5682,7 @@ }, "condition": "[not(empty(tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup')))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.network.network-security-group.{0}.{1}', tryGet(parameters('subnets')[copyIndex()], 'networkSecurityGroup', 'name'), parameters('resourceSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -6340,7 +6334,7 @@ }, "virtualNetwork": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.network.virtual-network.{0}', parameters('name')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -8067,7 +8061,7 @@ "bastionHost": { "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionHostName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -9386,7 +9380,7 @@ "jumpboxVM": { "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('jumpboxVmName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -17736,7 +17730,7 @@ }, "condition": "[and(parameters('enablePrivateNetworking'), or(empty(parameters('existingFoundryProjectResourceId')), not(contains(variables('aiRelatedDnsZoneIndices'), copyIndex()))))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('avm.res.network.private-dns-zone.{0}', split(variables('privateDnsZones')[copyIndex()], '.')[1])]", "properties": { "expressionEvaluationOptions": { @@ -20903,7 +20897,7 @@ }, "keyvault": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.key-vault.vault.{0}', variables('keyVaultName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -20920,9 +20914,7 @@ "tags": { "value": "[parameters('tags')]" }, - "sku": { - "value": "standard" - }, + "sku": "[if(parameters('enableScalability'), createObject('value', 'premium'), createObject('value', 'standard'))]", "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", "networkAcls": { "value": { @@ -24135,7 +24127,7 @@ "aiFoundryAiServices": { "condition": "[variables('aiFoundryAIservicesEnabled')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.cognitive-services.account.{0}', variables('aiFoundryAiServicesResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -24250,8 +24242,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "11586648700335054863" + "version": "0.39.26.7824", + "templateHash": "1936381873810101836" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service." @@ -25431,7 +25423,7 @@ "cognitive_service_dependencies": { "condition": "[not(variables('useExistingService'))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('cognitive_service_dependencies-{0}', uniqueString('cognitive_service_dependencies', deployment().name))]", "properties": { "expressionEvaluationOptions": { @@ -25483,8 +25475,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "8352858209491089788" + "version": "0.39.26.7824", + "templateHash": "17351518472581919759" } }, "definitions": { @@ -26521,7 +26513,7 @@ "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", @@ -27272,7 +27264,7 @@ "secretsExport": { "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", @@ -27296,8 +27288,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "2491273843075489892" + "version": "0.39.26.7824", + "templateHash": "4291957610087788581" } }, "definitions": { @@ -27416,7 +27408,7 @@ "aiProject": { "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('existingFoundryProjectResourceId'))))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -27450,8 +27442,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "346451728741152022" + "version": "0.39.26.7824", + "templateHash": "5108472911734987415" } }, "definitions": { @@ -27630,7 +27622,7 @@ "existing_cognitive_service_dependencies": { "condition": "[variables('useExistingService')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('existing_cognitive_service_dependencies-{0}', uniqueString('existing_cognitive_service_dependencies', deployment().name))]", "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", @@ -27687,8 +27679,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "8352858209491089788" + "version": "0.39.26.7824", + "templateHash": "17351518472581919759" } }, "definitions": { @@ -28725,7 +28717,7 @@ "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-cognitiveService-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", @@ -29476,7 +29468,7 @@ "secretsExport": { "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-secrets-kv', uniqueString(deployment().name, parameters('location')))]", "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", @@ -29500,8 +29492,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "2491273843075489892" + "version": "0.39.26.7824", + "templateHash": "4291957610087788581" } }, "definitions": { @@ -29620,7 +29612,7 @@ "aiProject": { "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('existingFoundryProjectResourceId'))))]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -29654,8 +29646,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "346451728741152022" + "version": "0.39.26.7824", + "templateHash": "5108472911734987415" } }, "definitions": { @@ -29912,8 +29904,8 @@ } }, "dependsOn": [ - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').aiServices)]", "logAnalyticsWorkspace", "userAssignedIdentity", "virtualNetwork" @@ -29921,7 +29913,7 @@ }, "cosmosDb": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.document-db.database-account.{0}', variables('cosmosDbResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -29984,7 +29976,7 @@ "zoneRedundant": "[if(parameters('enableRedundancy'), createObject('value', true()), createObject('value', false()))]", "capabilitiesToAdd": "[if(parameters('enableRedundancy'), createObject('value', null()), createObject('value', createArray('EnableServerless')))]", "automaticFailover": "[if(parameters('enableRedundancy'), createObject('value', true()), createObject('value', false()))]", - "failoverLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('failoverPriority', 0, 'isZoneRedundant', true(), 'locationName', variables('solutionLocation')), createObject('failoverPriority', 1, 'isZoneRedundant', true(), 'locationName', variables('cosmosDbHaLocation')))), createObject('value', createArray(createObject('locationName', variables('solutionLocation'), 'failoverPriority', 0, 'isZoneRedundant', parameters('enableRedundancy')))))]" + "failoverLocations": "[if(parameters('enableRedundancy'), createObject('value', createArray(createObject('failoverPriority', 0, 'isZoneRedundant', true(), 'locationName', parameters('cosmosLocation')), createObject('failoverPriority', 1, 'isZoneRedundant', true(), 'locationName', parameters('secondaryCosmosLocation')))), createObject('value', createArray(createObject('locationName', variables('solutionLocation'), 'failoverPriority', 0, 'isZoneRedundant', parameters('enableRedundancy')))))]" }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -33761,7 +33753,7 @@ }, "avmStorageAccount": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.storage.storage-account.{0}', variables('storageAccountName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -39531,7 +39523,7 @@ }, "saveStorageAccountSecretsInKeyVault": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('saveStorageAccountSecretsInKeyVault.{0}', variables('keyVaultName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -39575,7 +39567,7 @@ }, { "name": "ADLS-ACCOUNT-KEY", - "value": "[listOutputsWithSecureValues('avmStorageAccount', '2022-09-01').primaryAccessKey]" + "value": "[listOutputsWithSecureValues('avmStorageAccount', '2025-04-01').primaryAccessKey]" } ] } @@ -42703,7 +42695,7 @@ }, "sqlDBModule": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.sql.server.{0}', variables('sqlDbName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -42760,7 +42752,6 @@ "primaryUserAssignedIdentityResourceId": { "value": "[reference('userAssignedIdentity').outputs.resourceId.value]" }, - "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').sqlServer)).outputs.resourceId.value))), 'service', 'sqlServer', 'subnetResourceId', reference('virtualNetwork').outputs.pepsSubnetResourceId.value, 'tags', parameters('tags')))), createObject('value', createArray()))]", "firewallRules": "[if(not(parameters('enablePrivateNetworking')), createObject('value', createArray(createObject('endIpAddress', '255.255.255.255', 'name', 'AllowSpecificRange', 'startIpAddress', '0.0.0.0'), createObject('endIpAddress', '0.0.0.0', 'name', 'AllowAllWindowsAzureIps', 'startIpAddress', '0.0.0.0'))), createObject('value', createArray()))]", "tags": { "value": "[parameters('tags')]" @@ -49337,16 +49328,15 @@ } }, "dependsOn": [ - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').sqlServer)]", "logAnalyticsWorkspace", - "userAssignedIdentity", - "virtualNetwork" + "userAssignedIdentity" ] }, - "webServerFarm": { + "sqlDbPrivateEndpoint": { + "condition": "[parameters('enablePrivateNetworking')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.web.serverfarm.{0}', variables('webServerFarmResourceName')), 64)]", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.network.private-endpoint.sql-{0}', variables('solutionSuffix')), 64)]", "properties": { "expressionEvaluationOptions": { "scope": "inner" @@ -49354,7 +49344,10 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[variables('webServerFarmResourceName')]" + "value": "[format('pep-sql-{0}', variables('solutionSuffix'))]" + }, + "location": { + "value": "[variables('solutionLocation')]" }, "tags": { "value": "[parameters('tags')]" @@ -49362,21 +49355,34 @@ "enableTelemetry": { "value": "[parameters('enableTelemetry')]" }, - "location": { - "value": "[variables('solutionLocation')]" - }, - "reserved": { - "value": true + "subnetResourceId": { + "value": "[reference('virtualNetwork').outputs.pepsSubnetResourceId.value]" }, - "kind": { - "value": "linux" + "customNetworkInterfaceName": { + "value": "[format('nic-sql-{0}', variables('solutionSuffix'))]" }, - "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)))), createObject('value', null()))]", - "skuName": "[if(or(parameters('enableScalability'), parameters('enableRedundancy')), createObject('value', 'P1v3'), createObject('value', 'B3'))]", - "skuCapacity": { - "value": 1 + "privateLinkServiceConnections": { + "value": [ + { + "name": "[format('pl-sqlserver-{0}', variables('solutionSuffix'))]", + "properties": { + "privateLinkServiceId": "[reference('sqlDBModule').outputs.resourceId.value]", + "groupIds": [ + "sqlServer" + ] + } + } + ] }, - "zoneRedundant": "[if(parameters('enableRedundancy'), createObject('value', true()), createObject('value', false()))]" + "privateDnsZoneGroup": { + "value": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "[reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').sqlServer)).outputs.resourceId.value]" + } + ] + } + } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", @@ -49385,100 +49391,36 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.36.177.2456", - "templateHash": "16945786131371363466" + "version": "0.38.5.1644", + "templateHash": "16604612898799598358" }, - "name": "App Service Plan", - "description": "This module deploys an App Service Plan." + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." }, "definitions": { - "diagnosticSettingMetricsOnlyType": { + "privateDnsZoneGroupType": { "type": "object", "properties": { "name": { "type": "string", "nullable": true, "metadata": { - "description": "Optional. The name of diagnostic setting." + "description": "Optional. The name of the Private DNS Zone Group." } }, - "metricCategories": { + "privateDnsZoneGroupConfigs": { "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." - } - }, - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the category explicitly. Default is `true`." - } - } - } + "$ref": "#/definitions/privateDnsZoneGroupConfigType" }, - "nullable": true, - "metadata": { - "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": { - "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." + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." } } }, "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" - } + "__bicep_export!": true, + "description": "The type of a private dns zone group." } }, "lockType": { @@ -49514,7 +49456,31 @@ "metadata": { "description": "An AVM-aligned type for a lock.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" + } + } + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "description": "The type of a private DNS zone group configuration.", + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" } } }, @@ -49589,7 +49555,7 @@ "metadata": { "description": "An AVM-aligned type for a role assignment.", "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.1" } } } @@ -49597,114 +49563,800 @@ "parameters": { "name": { "type": "string", - "minLength": 1, - "maxLength": 60, "metadata": { - "description": "Required. Name of the app service plan." + "description": "Required. Name of the private endpoint resource to create." } }, - "skuName": { + "subnetResourceId": { "type": "string", - "defaultValue": "P1v3", "metadata": { - "example": " 'F1'\n 'B1'\n 'P1v3'\n 'I1v2'\n 'FC1'\n ", - "description": "Optional. The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones." + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." } }, - "skuCapacity": { - "type": "int", - "defaultValue": 3, - "metadata": { - "description": "Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, "metadata": { - "description": "Optional. Location for all resources." + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." } }, - "kind": { + "customNetworkInterfaceName": { "type": "string", - "defaultValue": "app", - "allowedValues": [ - "app", - "elastic", - "functionapp", - "windows", - "linux" - ], + "nullable": true, "metadata": { - "description": "Optional. Kind of server OS." + "description": "Optional. The custom name of the network interface attached to the private endpoint." } }, - "reserved": { - "type": "bool", - "defaultValue": "[equals(parameters('kind'), 'linux')]", + "ipConfigurations": { + "type": "array", "metadata": { - "description": "Conditional. Defaults to false when creating Windows/app App Service Plan. Required if creating a Linux App Service Plan and must be set to true." - } + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/ipConfigurations" + }, + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + }, + "nullable": true }, - "appServiceEnvironmentResourceId": { - "type": "string", - "defaultValue": "", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, "metadata": { - "description": "Optional. The Resource ID of the App Service Environment to use for the App Service Plan." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, - "workerTierName": { + "location": { "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Target worker tier assigned to the App Service plan." - } - }, - "perSiteScaling": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If true, apps assigned to this App Service plan can be scaled independently. If false, apps assigned to this App Service plan will scale to all instances of the plan." - } - }, - "elasticScaleEnabled": { - "type": "bool", - "defaultValue": "[greater(parameters('maximumElasticWorkerCount'), 1)]", - "metadata": { - "description": "Optional. Enable/Disable ElasticScaleEnabled App Service Plan." - } - }, - "maximumElasticWorkerCount": { - "type": "int", - "defaultValue": 1, - "metadata": { - "description": "Optional. Maximum number of total workers allowed for this ElasticScaleEnabled App Service Plan." - } - }, - "targetWorkerCount": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Scaling worker count." - } - }, - "targetWorkerSize": { - "type": "int", - "defaultValue": 0, - "allowedValues": [ - 0, - 1, - 2 - ], - "metadata": { - "description": "Optional. The instance size of the hosting plan (small, medium, or large)." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": "[if(or(startsWith(parameters('skuName'), 'P'), startsWith(parameters('skuName'), 'EP')), true(), false())]", + "defaultValue": "[resourceGroup().location]", "metadata": { - "description": "Optional. Zone Redundant server farms can only be used on Premium or ElasticPremium SKU tiers within ZRS Supported regions (https://learn.microsoft.com/en-us/azure/storage/common/redundancy-regions-zrs)." + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/tags" + }, + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + }, + "nullable": true + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs" + }, + "description": "Optional. Custom DNS configurations." + }, + "nullable": true + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/manualPrivateLinkServiceConnections" + }, + "description": "Conditional. 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. Required if `privateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "privateLinkServiceConnections": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/privateLinkServiceConnections" + }, + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + }, + "nullable": true + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "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": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.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": "2024-10-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": "[coalesce(tryGet(parameters('lock'), '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(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "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.38.5.1644", + "templateHash": "24141742673128945" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true, + "description": "The type of a private DNS zone group configuration." + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. 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." + } + } + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2024-10-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2024-10-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigs')].privateDnsZoneResourceId]" + } + } + } + ] + } + } + }, + "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', '2024-10-01', 'full').location]" + }, + "customDnsConfigs": { + "type": "array", + "metadata": { + "__bicep_resource_derived_type!": { + "source": "Microsoft.Network/privateEndpoints@2024-01-01#properties/properties/properties/customDnsConfigs", + "output": true + }, + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').sqlServer)]", + "sqlDBModule", + "virtualNetwork" + ] + }, + "webServerFarm": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2025-04-01", + "name": "[take(format('avm.res.web.serverfarm.{0}', variables('webServerFarmResourceName')), 64)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[variables('webServerFarmResourceName')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": { + "value": "[variables('solutionLocation')]" + }, + "reserved": { + "value": true + }, + "kind": { + "value": "linux" + }, + "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', if(variables('useExistingLogAnalytics'), parameters('existingLogAnalyticsWorkspaceId'), reference('logAnalyticsWorkspace').outputs.resourceId.value)))), createObject('value', null()))]", + "skuName": { + "value": "B3" + }, + "skuCapacity": { + "value": 1 + }, + "zoneRedundant": { + "value": false + } + }, + "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.36.177.2456", + "templateHash": "16945786131371363466" + }, + "name": "App Service Plan", + "description": "This module deploys an App Service Plan." + }, + "definitions": { + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "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." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "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": { + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "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." + } + }, + "notes": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the notes of the lock." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + }, + "roleAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.6.0" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 60, + "metadata": { + "description": "Required. Name of the app service plan." + } + }, + "skuName": { + "type": "string", + "defaultValue": "P1v3", + "metadata": { + "example": " 'F1'\n 'B1'\n 'P1v3'\n 'I1v2'\n 'FC1'\n ", + "description": "Optional. The name of the SKU will Determine the tier, size, family of the App Service Plan. This defaults to P1v3 to leverage availability zones." + } + }, + "skuCapacity": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "kind": { + "type": "string", + "defaultValue": "app", + "allowedValues": [ + "app", + "elastic", + "functionapp", + "windows", + "linux" + ], + "metadata": { + "description": "Optional. Kind of server OS." + } + }, + "reserved": { + "type": "bool", + "defaultValue": "[equals(parameters('kind'), 'linux')]", + "metadata": { + "description": "Conditional. Defaults to false when creating Windows/app App Service Plan. Required if creating a Linux App Service Plan and must be set to true." + } + }, + "appServiceEnvironmentResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The Resource ID of the App Service Environment to use for the App Service Plan." + } + }, + "workerTierName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Target worker tier assigned to the App Service plan." + } + }, + "perSiteScaling": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If true, apps assigned to this App Service plan can be scaled independently. If false, apps assigned to this App Service plan will scale to all instances of the plan." + } + }, + "elasticScaleEnabled": { + "type": "bool", + "defaultValue": "[greater(parameters('maximumElasticWorkerCount'), 1)]", + "metadata": { + "description": "Optional. Enable/Disable ElasticScaleEnabled App Service Plan." + } + }, + "maximumElasticWorkerCount": { + "type": "int", + "defaultValue": 1, + "metadata": { + "description": "Optional. Maximum number of total workers allowed for this ElasticScaleEnabled App Service Plan." + } + }, + "targetWorkerCount": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Scaling worker count." + } + }, + "targetWorkerSize": { + "type": "int", + "defaultValue": 0, + "allowedValues": [ + 0, + 1, + 2 + ], + "metadata": { + "description": "Optional. The instance size of the hosting plan (small, medium, or large)." + } + }, + "zoneRedundant": { + "type": "bool", + "defaultValue": "[if(or(startsWith(parameters('skuName'), 'P'), startsWith(parameters('skuName'), 'EP')), true(), false())]", + "metadata": { + "description": "Optional. Zone Redundant server farms can only be used on Premium or ElasticPremium SKU tiers within ZRS Supported regions (https://learn.microsoft.com/en-us/azure/storage/common/redundancy-regions-zrs)." } }, "lock": { @@ -49918,7 +50570,7 @@ }, "webSite": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('module.web-sites.{0}', variables('webSiteResourceName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -50030,8 +50682,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4298119334635398540" + "version": "0.39.26.7824", + "templateHash": "13074777962389399773" } }, "definitions": { @@ -51008,7 +51660,7 @@ "count": "[length(coalesce(parameters('configs'), createArray()))]" }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-Site-Config-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "properties": { "expressionEvaluationOptions": { @@ -51043,8 +51695,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "4653685834544796273" + "version": "0.39.26.7824", + "templateHash": "11666262061409473778" }, "name": "Site App Settings", "description": "This module deploys a Site App Setting." @@ -51189,7 +51841,7 @@ "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" }, "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[format('{0}-app-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", @@ -52015,7 +52667,7 @@ }, "searchService": { "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "[take(format('avm.res.search.search-service.{0}', variables('aiSearchName')), 64)]", "properties": { "expressionEvaluationOptions": { @@ -52081,9 +52733,7 @@ "replicaCount": { "value": 1 }, - "sku": { - "value": "standard" - }, + "sku": "[if(parameters('enableScalability'), createObject('value', 'standard'), createObject('value', 'basic'))]", "semanticSearch": { "value": "free" }, @@ -54395,7 +55045,7 @@ "existing_AIProject_SearchConnectionModule": { "condition": "[variables('useExistingAiFoundryAiProject')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "aiProjectSearchConnectionDeployment", "subscriptionId": "[variables('aiFoundryAiServicesSubscriptionId')]", "resourceGroup": "[variables('aiFoundryAiServicesResourceGroupName')]", @@ -54430,8 +55080,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "6038840175458269917" + "version": "0.39.26.7824", + "templateHash": "904007681755275486" } }, "parameters": { @@ -54499,7 +55149,7 @@ "searchServiceToExistingAiServicesRoleAssignment": { "condition": "[variables('useExistingAiFoundryAiProject')]", "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", + "apiVersion": "2025-04-01", "name": "searchToExistingAiServices-roleAssignment", "subscriptionId": "[variables('aiFoundryAiServicesSubscriptionId')]", "resourceGroup": "[variables('aiFoundryAiServicesResourceGroupName')]", @@ -54525,8 +55175,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.37.4.10188", - "templateHash": "3644919950024112374" + "version": "0.39.26.7824", + "templateHash": "10276790018915749779" } }, "parameters": { diff --git a/infra/main.parameters.json b/infra/main.parameters.json index de31ba4b..a1159e29 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -8,6 +8,9 @@ "cosmosLocation": { "value": "${AZURE_ENV_COSMOS_LOCATION}" }, + "secondaryCosmosLocation": { + "value": "${AZURE_ENV_COSMOS_SECONDARY_LOCATION}" + }, "gptModelDeploymentType": { "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" }, diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index 23621267..607e424f 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -8,6 +8,9 @@ "cosmosLocation": { "value": "${AZURE_ENV_COSMOS_LOCATION}" }, + "secondaryCosmosLocation": { + "value": "${AZURE_ENV_COSMOS_SECONDARY_LOCATION}" + }, "gptModelDeploymentType": { "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" },