diff --git a/.github/workflows/deploy-waf.yml b/.github/workflows/deploy-waf.yml index 8ec0a5e19..0427638d0 100644 --- a/.github/workflows/deploy-waf.yml +++ b/.github/workflows/deploy-waf.yml @@ -109,13 +109,15 @@ jobs: --resource-group ${{ env.RESOURCE_GROUP_NAME }} \ --template-file infra/main.bicep \ --parameters \ - environmentName=${{ env.SOLUTION_PREFIX }} \ - useWafAlignedArchitecture=true \ - aiDeploymentsLocation='${{ env.AZURE_LOCATION }}' \ + solutionName=${{ env.SOLUTION_PREFIX }} \ + location="${{ env.AZURE_LOCATION }}" \ + azureAiServiceLocation='${{ env.AZURE_LOCATION }}' \ gptModelCapacity=5 \ - virtualMachineConfiguration='{"adminUsername": "adminuser", "adminPassword": "P@ssw0rd1234"}' \ - logAnalyticsWorkspaceConfiguration='{"existingWorkspaceResourceId": ""}' - + enableTelemetry=true \ + enableMonitoring=true \ + enablePrivateNetworking=true \ + enableScalability=true \ + - name: Send Notification on Failure if: failure() diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 747d8de53..71770955a 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -129,19 +129,16 @@ jobs: --resource-group ${{ env.RESOURCE_GROUP_NAME }} \ --template-file infra/main.bicep \ --parameters \ - environmentName=${{ env.SOLUTION_PREFIX }} \ - solutionLocation="${{ env.AZURE_LOCATION }}" \ - modelDeploymentType="GlobalStandard" \ + solutionName=${{ env.SOLUTION_PREFIX }} \ + location="${{ env.AZURE_LOCATION }}" \ + gptModelDeploymentType="GlobalStandard" \ gptModelName="gpt-4o" \ gptModelVersion="2024-08-06" \ - imageTag="${IMAGE_TAG}" \ - useWafAlignedArchitecture=false \ - aiDeploymentsLocation='${{ env.AZURE_LOCATION }}' \ + backendContainerImageTag="${IMAGE_TAG}" \ + frontendContainerImageTag="${IMAGE_TAG}" \ + azureAiServiceLocation='${{ env.AZURE_LOCATION }}' \ gptModelCapacity=150 \ - logAnalyticsWorkspaceConfiguration='{"dataRetentionInDays": 30, "existingWorkspaceResourceId": ""}' \ - applicationInsightsConfiguration='{"retentionInDays": 30}' \ - virtualNetworkConfiguration='{"enabled": false}' \ - webServerFarmConfiguration='{"skuCapacity": 1, "skuName": "B2"}' \ + createdBy="Pipeline" \ --output json - name: Extract Web App and API App URLs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6392f559b..92d60e212 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,7 +51,7 @@ jobs: - name: Run tests with coverage if: env.skip_tests == 'false' run: | - pytest --cov=. --cov-report=term-missing --cov-report=xml + pytest --cov=. --cov-report=term-missing --cov-report=xml --ignore=tests/e2e-test/tests - name: Skip coverage report if no tests if: env.skip_tests == 'true' diff --git a/.gitignore b/.gitignore index d360058d0..089d2bcb1 100644 --- a/.gitignore +++ b/.gitignore @@ -460,4 +460,7 @@ __pycache__/ .azure .github/copilot-instructions.md # Ignore sample code folder -data/sample_code/ \ No newline at end of file +data/sample_code/ +# Bicep local files +*.local*.bicepparam +*.local*.parameters.json \ No newline at end of file diff --git a/azure.yaml b/azure.yaml index 26522f5db..ddb2538fa 100644 --- a/azure.yaml +++ b/azure.yaml @@ -3,4 +3,38 @@ name: multi-agent-custom-automation-engine-solution-accelerator metadata: template: multi-agent-custom-automation-engine-solution-accelerator@1.0 requiredVersions: - azd: ">=1.15.0 !=1.17.1" \ No newline at end of file + azd: ">=1.15.0 !=1.17.1" +hooks: + postdeploy: + windows: + run: | + Write-Host "To upload Team Configurations to Cosmos. Run the following command in PowerShell:" + Write-Host "infra\scripts\Upload-Team-Config.ps1" -ForegroundColor Cyan + Write-Host "" + Write-Host "To index Sample Data into Azure Search. Run the following command in PowerShell:" + Write-Host "infra\scripts\Process-Sample-Data.ps1" -ForegroundColor Cyan + Write-Host "" + Write-Host "To upload team configurations and index sample data both in one command, you can use the following command in PowerShell:" + Write-Host "infra\scripts\Team-Config-And-Data.ps1" -ForegroundColor Cyan + Write-Host "" + Write-Host "You can access the deployed Frontend application at the following URL:" + Write-Host "https://$env:webSiteDefaultHostname" -ForegroundColor Cyan + shell: pwsh + interactive: true + posix: + run: | + Blue='\033[0;34m' + NC='\033[0m' + echo "To upload Team Configurations to Cosmos. Run the following command in Bash:" + echo "${Blue}bash infra/scripts/upload_team_config.sh" + echo "" + echo "${NC}To index Sample Data into Azure Search. Run the following command in Bash:" + echo "${Blue}bash infra/scripts/process_sample_data.sh" + echo "" + echo "${NC}To upload team configurations and index sample data both in one command, you can use the following command in Bash:" + echo "${Blue}bash infra/scripts/team_config_and_data.sh" + echo "" + echo "${NC}You can access the deployed Frontend application at the following URL:" + echo "${Blue}https://$webSiteDefaultHostname" + shell: sh + interactive: true diff --git a/azure_custom.yaml b/azure_custom.yaml index 926a8f730..8006855e3 100644 --- a/azure_custom.yaml +++ b/azure_custom.yaml @@ -38,4 +38,39 @@ services: shell: sh run: bash ../../infra/scripts/package_frontend.sh interactive: true - continueOnError: false \ No newline at end of file + continueOnError: false + +hooks: + postdeploy: + windows: + run: | + Write-Host "To upload Team Configurations to Cosmos. Run the following command in PowerShell:" + Write-Host "infra\scripts\Upload-Team-Config.ps1" -ForegroundColor Cyan + Write-Host "" + Write-Host "To index Sample Data into Azure Search. Run the following command in PowerShell:" + Write-Host "infra\scripts\Process-Sample-Data.ps1" -ForegroundColor Cyan + Write-Host "" + Write-Host "If you want to run both scripts as single command, you can use the following command in PowerShell:" + Write-Host "infra\scripts\Team-Config-And-Data.ps1" -ForegroundColor Cyan + Write-Host "" + Write-Host "You can access the deployed Frontend application at the following URL:" + Write-Host "https://$env:webSiteDefaultHostname" -ForegroundColor Cyan + shell: pwsh + interactive: true + posix: + run: | + Blue='\033[0;34m' + NC='\033[0m' + echo "To upload Team Configurations to Cosmos. Run the following command in Bash:" + echo "${Blue}bash infra/scripts/upload_team_config.sh" + echo "" + echo "${NC}To index Sample Data into Azure Search. Run the following command in Bash:" + echo "${Blue}bash infra/scripts/process_sample_data.sh" + echo "" + echo "${NC}If you want to run both scripts as single command, you can use the following command in Bash:" + echo "${Blue}bash infra/scripts/team_config_and_data.sh" + echo "" + echo "${NC}You can access the deployed Frontend application at the following URL:" + echo "${Blue}https://$webSiteDefaultHostname" + shell: sh + interactive: true \ No newline at end of file diff --git a/docs/CustomizingAzdParameters.md b/docs/CustomizingAzdParameters.md index bc28fc345..79830249a 100644 --- a/docs/CustomizingAzdParameters.md +++ b/docs/CustomizingAzdParameters.md @@ -19,6 +19,8 @@ By default this template will use the environment name as the prefix to prevent | `AZURE_ENV_IMAGETAG` | string | `latest` | Docker image tag used for container deployments. | | `AZURE_ENV_ENABLE_TELEMETRY` | bool | `true` | Enables telemetry for monitoring and diagnostics. | | `AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID` | string | Guide to get your [Existing Workspace ID](/docs/re-use-log-analytics.md) | Set this if you want to reuse an existing Log Analytics Workspace instead of creating a new one. | +| `AZURE_ENV_VM_ADMIN_USERNAME` | string | `take(newGuid(), 20)` | The administrator username for the virtual machine. | +| `AZURE_ENV_VM_ADMIN_PASSWORD` | string | `newGuid()` | The administrator password for the virtual machine. | --- ## How to Set a Parameter diff --git a/docs/DeploymentGuide.md b/docs/DeploymentGuide.md index 165cf320d..245eacc1e 100644 --- a/docs/DeploymentGuide.md +++ b/docs/DeploymentGuide.md @@ -26,17 +26,41 @@ Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass This will allow the scripts to run for the current session without permanently changing your system's policy. +### **Azure Developer CLI (azd) Requirement** + +Ensure that you are using the latest version of the [Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview). +The `azd` version must be **1.18.0 or higher**. + +Upgrade commands by OS: + +* **Windows (using winget):** + + ```bash + winget install microsoft.azd + ``` + +* **Linux (using apt):** + + ```bash + curl -fsSL https://aka.ms/install-azd.sh | bash + ``` + +* **macOS (using Homebrew):** + + ```bash + brew update && brew tap azure/azd && brew install azd + ``` + ## Deployment Options & Steps ### Sandbox or WAF Aligned Deployment Options The [`infra`](../infra) folder of the Multi Agent Solution Accelerator contains the [`main.bicep`](../infra/main.bicep) Bicep script, which defines all Azure infrastructure components for this solution. -When running `azd up`, you’ll now be prompted to choose between a **WAF-aligned configuration** and a **sandbox configuration** using a simple selection: +By default, the `azd up` command uses the [`main.parameters.json`](../infra/main.parameters.json) file to deploy the solution. This file is pre-configured for a **sandbox environment** — ideal for development and proof-of-concept scenarios, with minimal security and cost controls for rapid iteration. -- A **sandbox environment** — ideal for development and proof-of-concept scenarios, with minimal security and cost controls for rapid iteration. +For **production deployments**, the repository also provides [`main.waf.parameters.json`](../infra/main.waf.parameters.json), which applies a [Well-Architected Framework (WAF) aligned](https://learn.microsoft.com/en-us/azure/well-architected/) configuration. This option enables additional Azure best practices for reliability, security, cost optimization, operational excellence, and performance efficiency, such as: -- A **production deployments environment**, which applies a [Well-Architected Framework (WAF) aligned](https://learn.microsoft.com/en-us/azure/well-architected/) configuration. This option enables additional Azure best practices for reliability, security, cost optimization, operational excellence, and performance efficiency, such as: - Enhanced network security (e.g., Network protection with private endpoints) - Stricter access controls and managed identities - Logging, monitoring, and diagnostics enabled by default @@ -44,24 +68,26 @@ When running `azd up`, you’ll now be prompted to choose between a **WAF-aligne **How to choose your deployment configuration:** -When prompted during `azd up`: +* Use the default `main.parameters.json` file for a **sandbox/dev environment** +* For a **WAF-aligned, production-ready deployment**, copy the contents of `main.waf.parameters.json` into `main.parameters.json` before running `azd up` -![useWAFAlignedArchitecture](images/macae_waf_prompt.png) +--- -- Select **`true`** to deploy a **WAF-aligned, production-ready environment** -- Select **`false`** to deploy a **lightweight sandbox/dev environment** +### VM Credentials Configuration + +By default, the solution sets the VM administrator username and password from environment variables. +If you do not configure these values, a randomly generated GUID will be used for both the username and password. + +To set your own VM credentials before deployment, use: + +```sh +azd env set AZURE_ENV_VM_ADMIN_USERNAME +azd env set AZURE_ENV_VM_ADMIN_PASSWORD +``` > [!TIP] > Always review and adjust parameter values (such as region, capacity, security settings and log analytics workspace configuration) to match your organization’s requirements before deploying. For production, ensure you have sufficient quota and follow the principle of least privilege for all identities and role assignments. -> To reuse an existing Log Analytics workspace, update the existingWorkspaceResourceId field under the logAnalyticsWorkspaceConfiguration parameter in the .bicep file with the resource ID of your existing workspace. -For example: -``` -param logAnalyticsWorkspaceConfiguration = { - dataRetentionInDays: 30 - existingWorkspaceResourceId: '/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/' -} -``` > [!IMPORTANT] > The WAF-aligned configuration is under active development. More Azure Well-Architected recommendations will be added in future updates. @@ -213,11 +239,51 @@ Once you've opened the project in [Codespaces](#github-codespaces), [Dev Contain - This deployment will take _4-6 minutes_ to provision the resources in your account and set up the solution with sample data. - If you encounter an error or timeout during deployment, changing the location may help, as there could be availability constraints for the resources. -5. Once the deployment has completed successfully, 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`. +5. After deployment completes, you can upload Team Configurations using command printed in the terminal. The command will look like one of the following. Run the appropriate command for your shell from the project root: + + - **For Bash (Linux/macOS/WSL):** + ```bash + bash infra/scripts/upload_team_config.sh + ``` + + - **For PowerShell (Windows):** + ```powershell + infra\scripts\Upload-Team-Config.ps1 + ``` + +6. After deployment completes, you can index Sample Data into Search Service using command printed in the terminal. The command will look like one of the following. Run the appropriate command for your shell from the project root: -6. When Deployment is complete, follow steps in [Set Up Authentication in Azure App Service](../docs/azure_app_service_auth_setup.md) to add app authentication to your web app running on Azure App Service + - **For Bash (Linux/macOS/WSL):** + ```bash + bash infra/scripts/process_sample_data.sh + ``` -7. If you are done trying out the application, you can delete the resources by running `azd down`. + - **For PowerShell (Windows):** + ```powershell + infra\scripts\Process-Sample-Data.ps1 + ``` + +7. To upload team configurations and index sample data in one step. Run the appropriate command for your shell from the project root: + + - **For Bash (Linux/macOS/WSL):** + ```bash + bash infra/scripts/team_config_and_data.sh + ``` + + - **For PowerShell (Windows):** + ```powershell + infra\scripts\Team-Config-And-Data.ps1 + ``` + +8. Once the deployment has completed successfully, 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`. + +9. When Deployment is complete, follow steps in [Set Up Authentication in Azure App Service](../docs/azure_app_service_auth_setup.md) to add app authentication to your web app running on Azure App Service + +10. If you are done trying out the application, you can delete the resources by running `azd down`. + + +### 🛠️ Troubleshooting + If you encounter any issues during the deployment process, please refer [troubleshooting](../docs/TroubleShootingSteps.md) document for detailed steps and solutions. # Local setup @@ -324,27 +390,39 @@ The files for the dev container are located in `/.devcontainer/` folder. - Update the `.env` file with the required values from your Azure resource group in Azure Portal App Service environment variables. - Alternatively, if resources were provisioned using `azd provision` or `azd up`, a `.env` file is automatically generated in the `.azure//.env` - file. To get your `` run `azd env list` to see which env is default. + file. You can copy the contents of this file into your backend `.env` file. + + _**Note**: To get your `` run `azd env list` to see which env is default._ 6. **Fill in the `.env` file:** - Use the output from the deployment or check the Azure Portal under "Deployments" in the resource group. - Make sure to set APP_ENV to "**dev**" in `.env` file. + - For local development, make sure to include below env variables in the `.env` + - `BACKEND_API_URL=http://localhost:8000` + - `FRONTEND_SITE_NAME=http://127.0.0.1:3000` . 7. **(Optional) Set up a virtual environment:** - If you are using `venv`, create and activate your virtual environment for both the frontend and backend folders. -8. **Install requirements - frontend:** +8. **Install requirements - Backend:** - - In each of the frontend and backend folders - - Open a terminal in the `src` folder and run: + - To install the requirement for backend - + Open a terminal in the `src/backend` folder and run: ```bash - pip install -r requirements.txt + pip install uv + uv sync ``` 9. **Build the frontend (important):** + - To install the requirement for frontend - + Open a terminal in the `src/frontend` folder and run: + ```bash + pip install -r requirements.txt + ``` + - Before running the frontend server, you must build the frontend to generate the necessary `build/assets` directory. From the `src/frontend` directory, run: @@ -356,7 +434,7 @@ The files for the dev container are located in `/.devcontainer/` folder. 10. **Run the application:** -- From the src/backend directory: +- From the `src/backend` directory activate the virtual environment created through step 8 and Run: ```bash python app_kernel.py @@ -368,8 +446,22 @@ python app_kernel.py python frontend_server.py ``` -10. Open a browser and navigate to `http://localhost:3000` -11. To see swagger API documentation, you can navigate to `http://localhost:8000/docs` +or Run + + ```bash + npm run dev + ``` + +11. Open a browser and navigate to `http://localhost:3000` +12. To see swagger API documentation, you can navigate to `http://localhost:8000/docs` + +## Deploy Your local changes +To Deploy your local changes rename the below files. + 1. Rename `azure.yaml` to `azure_custom2.yaml` and `azure_custom.yaml` to `azure.yaml`. + 2. Go to `infra` directory + - Remove `main.bicep` to `main_custom2.bicep` and `main_custom.bicep` to `main.bicep`. +Continue with the [deploying steps](#deploying-with-azd). + ## Debugging the solution locally diff --git a/docs/LocalDeployment.md b/docs/LocalDeployment.md deleted file mode 100644 index e7ebe0065..000000000 --- a/docs/LocalDeployment.md +++ /dev/null @@ -1,180 +0,0 @@ -# Guide to local development - -## Requirements: - -- Python 3.10 or higher + PIP -- Azure CLI, and an Azure Subscription -- Visual Studio Code IDE - -# Local setup - -> **Note for macOS Developers**: If you are using macOS on Apple Silicon (ARM64) the DevContainer will **not** work. This is due to a limitation with the Azure Functions Core Tools (see [here](https://github.com/Azure/azure-functions-core-tools/issues/3112)). We recommend using the [Non DevContainer Setup](./NON_DEVCONTAINER_SETUP.md) instructions to run the accelerator locally. - -The easiest way to run this accelerator is in a VS Code Dev Containers, which will open the project in your local VS Code using the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers): - -1. Start Docker Desktop (install it if not already installed) -1. Open the project: - [![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/microsoft/Multi-Agent-Custom-Automation-Engine-Solution-Accelerator) - -1. In the VS Code window that opens, once the project files show up (this may take several minutes), open a terminal window - -## Detailed Development Container setup instructions - -The solution contains a [development container](https://code.visualstudio.com/docs/remote/containers) with all the required tooling to develop and deploy the accelerator. To deploy the Multi Agent Solution accelerator using the provided development container you will also need: - -* [Visual Studio Code](https://code.visualstudio.com) -* [Remote containers extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) - -If you are running this on Windows, we recommend you clone this repository in [WSL](https://code.visualstudio.com/docs/remote/wsl) - -```cmd -git clone https://github.com/microsoft/Multi-Agent-Custom-Automation-Engine-Solution-Accelerator -``` - -Open the cloned repository in Visual Studio Code and connect to the development container. - -```cmd -code . -``` - -!!! tip - Visual Studio Code should recognize the available development container and ask you to open the folder using it. For additional details on connecting to remote containers, please see the [Open an existing folder in a container](https://code.visualstudio.com/docs/remote/containers#_quick-start-open-an-existing-folder-in-a-container) quickstart. - -When you start the development container for the first time, the container will be built. This usually takes a few minutes. **Please use the development container for all further steps.** - -The files for the dev container are located in `/.devcontainer/` folder. - -## Local deployment and debugging: - -1. **Clone the repository.** - -2. **Log into the Azure CLI:** - - - Check your login status using: - ```bash - az account show - ``` - - If not logged in, use: - ```bash - az login - ``` - - To specify a tenant, use: - ```bash - az login --tenant - ``` - -3. **Create a Resource Group:** - - - You can create it either through the Azure Portal or the Azure CLI: - ```bash - az group create --name --location EastUS2 - ``` - -4. **Deploy the Bicep template:** - - - You can use the Bicep extension for VSCode (Right-click the `.bicep` file, then select "Show deployment plane") or use the Azure CLI: - ```bash - az deployment group create -g -f infra/main.bicep --query 'properties.outputs' - ``` - - **Note**: You will be prompted for a `principalId`, which is the ObjectID of your user in Entra ID. To find it, use the Azure Portal or run: - ```bash - az ad signed-in-user show --query id -o tsv - ``` - You will also be prompted for locations for Cosmos and OpenAI services. This is to allow separate regions where there may be service quota restrictions. - - - **Additional Notes**: - - **Role Assignments in Bicep Deployment:** - - The **macae-dev.bicep** deployment includes the assignment of the appropriate roles to AOAI and Cosmos services. If you want to modify an existing implementation—for example, to use resources deployed as part of the simple deployment for local debugging—you will need to add your own credentials to access the Cosmos and AOAI services. You can add these permissions using the following commands: - ```bash - az cosmosdb sql role assignment create --resource-group --account-name --role-definition-name "Cosmos DB Built-in Data Contributor" --principal-id --scope /subscriptions//resourceGroups//providers/Microsoft.DocumentDB/databaseAccounts/ - ``` - - ```bash - az role assignment create --assignee --role "Azure AI User" --scope /subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts/ - ``` - **Using a Different Database in Cosmos:** - - You can set the solution up to use a different database in Cosmos. For example, you can name it something like autogen-dev. To do this: - 1. Change the environment variable **COSMOSDB_DATABASE** to the new database name. - 2. You will need to create the database in the Cosmos DB account. You can do this from the Data Explorer pane in the portal, click on the drop down labeled “_+ New Container_” and provide all the necessary details. - -6. **Create a `.env` file:** - - - Navigate to the `src\backend` folder and create a `.env` file based on the provided `.env.sample` file. - - Update the `.env` file with the required values from your Azure resource group in Azure Portal App Service environment variables. - - Alternatively, if resources were - provisioned using `azd provision` or `azd up`, a `.env` file is automatically generated in the `.azure//.env` - file. To get your `` run `azd env list` to see which env is default. - -7. **Fill in the `.env` file:** - - - Use the output from the deployment or check the Azure Portal under "Deployments" in the resource group. - - Make sure to set APP_ENV to "**dev**" in `.env` file. - -8. **(Optional) Set up a virtual environment:** - - - If you are using `venv`, create and activate your virtual environment for both the frontend and backend folders. - -9. **Install requirements - frontend:** - - - In each of the frontend and backend folders - - Open a terminal in the `src` folder and run: - ```bash - pip install -r requirements.txt - ``` - -9. **Build the frontend (important):** - - - Before running the frontend server, you must build the frontend to generate the necessary `build/assets` directory. - - From the `src/frontend` directory, run: - - ```bash - npm install - npm run build - ``` - -11. **Run the application:** - - From the src/backend directory: - ```bash - python app_kernel.py - ``` - - In a new terminal from the src/frontend directory - ```bash - python frontend_server.py - ``` - -10. Open a browser and navigate to `http://localhost:3000` -11. To see swagger API documentation, you can navigate to `http://localhost:8000/docs` - -## Debugging the solution locally - -You can debug the API backend running locally with VSCode using the following launch.json entry: - -``` - { - "name": "Python Debugger: Backend", - "type": "debugpy", - "request": "launch", - "cwd": "${workspaceFolder}/src/backend", - "module": "uvicorn", - "args": ["app:app", "--reload"], - "jinja": true - } -``` -To debug the python server in the frontend directory (frontend_server.py) and related, add the following launch.json entry: - -``` - { - "name": "Python Debugger: Frontend", - "type": "debugpy", - "request": "launch", - "cwd": "${workspaceFolder}/src/frontend", - "module": "uvicorn", - "args": ["frontend_server:app", "--port", "3000", "--reload"], - "jinja": true - } -``` - diff --git a/docs/SetUpGroundingWithBingSearch.md b/docs/SetUpGroundingWithBingSearch.md new file mode 100644 index 000000000..8ccdd2302 --- /dev/null +++ b/docs/SetUpGroundingWithBingSearch.md @@ -0,0 +1,99 @@ + +# 🌐 Grounding with Bing Search — Quick Setup + +This guide walks you through setting up Grounding with Bing Search and connecting it to your Azure AI Foundry project. This tool enables your AI agents to retrieve real-time public web data, enhancing responses with up-to-date information. + +--- + +## ✅ Prerequisites + +- An active **Azure subscription** +- **Azure CLI** installed and logged in (`az login`) +- A **resource group** created +- Register the Bing provider (one-time setup): + + ```bash + az provider register --namespace Microsoft.Bing + +⚠️ **Important:** +Bing Search Grounding only supports **API key authentication**. +Ensure your **Azure AI Foundry account has Local Authentication enabled**. +If local auth is disabled, you will not be able to connect Bing Search. + +--- + +## 🚀 Step 1: Create a Bing Search Grounding Resource + +### Option A — Azure Portal + +1. In the [Azure Portal](https://portal.azure.com), search for **Bing Search (Grounding)**. +2. Click **Create**. +3. Select your **Subscription** and **Resource Group**. +4. Enter a **Resource Name** and choose a **Pricing Tier (SKU)**. +5. At the bottom of the form, tick the required checkbox: + ✅ *“I confirm I have read and understood the notice above.”* + (You cannot proceed without this.) +6. Click **Review + Create** → **Create**. + +--- + +### Option B — Azure CLI + +Set your variables (replace with your own values): + +```bash +RESOURCE_GROUP="" +ACCOUNT_NAME="" +LOCATION="global" # must be 'global' +SKU="G1" +KIND="Bing.Grounding" + +SUBSCRIPTION_ID=$(az account show --query id --output tsv) +RESOURCE_ID="/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/microsoft.bing/accounts/$ACCOUNT_NAME" +``` + +Create the resource: + +```bash +az rest --method put \ + --url "https://management.azure.com$RESOURCE_ID?api-version=2020-06-10" \ + --body '{ + "location": "'$LOCATION'", + "kind": "'$KIND'", + "sku": { "name": "'$SKU'" }, + "properties": {} + }' +``` + +Verify creation: + +```bash +az resource show --ids "$RESOURCE_ID" --api-version 2020-06-10 -o table +``` + +--- + +## 🔗 Step 2: Connect Bing Search to Azure AI Foundry + +1. Open your **Azure AI Foundry project** in the [AI Studio portal](https://ai.azure.com). +2. Go to **Management center** → **Connected resources**. +3. Click **+ Add connection**. +4. Select **Grounding with Bing Search**. +5. Choose the Bing resource you created and click **Create**. + +--- + +## 💡 Why Use Bing Search Grounding? + +* Provides **real-time information** to enrich AI responses. +* Helps LLMs give answers with **up-to-date knowledge** beyond training data. +* Useful for scenarios like **news, research, or dynamic queries**. + +--- + +## 📚 Additional Resources + +* [Grounding with Bing Search (overview)](https://learn.microsoft.com/en-us/azure/ai-foundry/agents/how-to/tools/bing-grounding) — Learn how the tool works, pricing, privacy notes, and how real-time search is integrated. ([Microsoft Learn][1]) +* [Grounding with Bing Search code samples](https://learn.microsoft.com/en-us/azure/ai-foundry/agents/how-to/tools/bing-code-samples?source=recommendations&pivots=portal) — SDK and REST examples for using Bing grounding. ([Microsoft Learn][2]) + +--- \ No newline at end of file diff --git a/docs/TroubleShootingSteps.md b/docs/TroubleShootingSteps.md new file mode 100644 index 000000000..1a194a35d --- /dev/null +++ b/docs/TroubleShootingSteps.md @@ -0,0 +1,301 @@ +# 🛠️ 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 + + +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: + ``` + 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 u 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/quota_check.md) file for details. + +
+ +
+DeploymentModelNotSupported + + - 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 + +- 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. + + ``` + 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} + ``` +- 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) + +
+ +💡 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 [MACAE Github Issues](https://github.com/microsoft/Multi-Agent-Custom-Automation-Engine-Solution-Accelerator/issues) for further support. diff --git a/docs/images/AzureHomePage.png b/docs/images/AzureHomePage.png new file mode 100644 index 000000000..cb3ce189a Binary files /dev/null and b/docs/images/AzureHomePage.png differ diff --git a/docs/images/resourcegroup1.png b/docs/images/resourcegroup1.png new file mode 100644 index 000000000..ee230f53c Binary files /dev/null and b/docs/images/resourcegroup1.png differ diff --git a/infra/main.bicep b/infra/main.bicep index 4a2bb7204..ce002e08e 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -1,309 +1,361 @@ -metadata name = 'Multi-Agent Custom Automation Engine' -metadata description = 'This module contains the resources required to deploy the Multi-Agent Custom Automation Engine solution accelerator for both Sandbox environments and WAF aligned environments.' - -@description('Set to true if you want to deploy WAF-aligned infrastructure.') -param useWafAlignedArchitecture bool - -@description('Use this parameter to use an existing AI project resource ID') -param existingFoundryProjectResourceId string = '' - -@description('Required. Name of the environment to deploy the solution into.') -param environmentName string +// // ========== main.bicep ========== // +targetScope = 'resourceGroup' -@description('Required. Location for all Resources except AI Foundry.') -param solutionLocation string = resourceGroup().location - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true - -param existingLogAnalyticsWorkspaceId string = '' - -param azureopenaiVersion string = '2025-01-01-preview' +metadata name = 'Multi-Agent Custom Automation Engine' +metadata description = '''This module contains the resources required to deploy the [Multi-Agent Custom Automation Engine solution accelerator](https://github.com/microsoft/Multi-Agent-Custom-Automation-Engine-Solution-Accelerator) for both Sandbox environments and WAF aligned environments. + +> **Note:** This module is not intended for broad, generic use, as it was designed by the Commercial Solution Areas CTO team, as a Microsoft Solution Accelerator. Feature requests and bug fix requests are welcome if they support the needs of this organization but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. This module will likely be updated to leverage AVM resource modules in the future. This may result in breaking changes in upcoming versions when these features are implemented. +''' + +@description('Optional. A unique application/solution name for all resources in this deployment. This should be 3-16 characters long.') +@minLength(3) +@maxLength(16) +param solutionName string = 'macae' + +@maxLength(5) +@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') +param solutionUniqueText string = take(uniqueString(subscription().id, resourceGroup().name, solutionName), 5) + +@metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for all services. 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/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).') +@allowed([ + 'australiaeast' + 'centralus' + 'eastasia' + 'eastus' + 'eastus2' + 'japaneast' + 'northeurope' + 'southeastasia' + 'westeurope' + 'uksouth' +]) +param location string //Get the current deployer's information var deployerInfo = deployer() var deployingUserPrincipalId = deployerInfo.objectId // Restricting deployment to only supported Azure OpenAI regions validated with GPT-4o model +@allowed(['australiaeast', 'eastus2', 'francecentral', 'japaneast', 'norwayeast', 'swedencentral', 'uksouth', 'westus']) @metadata({ - azd : { + azd: { type: 'location' - usageName : [ - 'OpenAI.GlobalStandard.gpt-4o, 150' + usageName: [ + 'OpenAI.GlobalStandard.o4-mini, 50' + 'OpenAI.GlobalStandard.gpt4.1-mini, 50' ] } }) -@allowed(['australiaeast', 'eastus2', 'francecentral', 'japaneast', 'norwayeast', 'swedencentral', 'uksouth', 'westus']) -@description('Azure OpenAI Location') -param aiDeploymentsLocation string +@description('Required. Location for all AI service resources. This should be one of the supported Azure AI Service locations.') +param azureAiServiceLocation string @minLength(1) -@description('Name of the GPT model to deploy:') -param gptModelName string = 'gpt-4o' +@description('Optional. Name of the GPT model to deploy:') +param gptModelName string = 'gpt-4.1-mini' -param gptModelVersion string = '2024-08-06' +@description('Optional. Version of the GPT model to deploy. Defaults to 2025-04-14.') +param gptModelVersion string = '2025-04-14' @minLength(1) -@description('GPT model deployment type:') -param modelDeploymentType string = 'GlobalStandard' +@description('Optional. Name of the GPT Reasoning model to deploy:') +param gptReasoningModelName string = 'o4-mini' -@description('Optional. AI model deployment token capacity.') -param gptModelCapacity int = 150 +@description('Optional. Version of the GPT Reasoning model to deploy. Defaults to 2025-04-14.') +param gptReasoningModelVersion string = '2025-04-16' -@description('Set the image tag for the container images used in the solution. Default is "latest".') -param imageTag string = 'latest' +@description('Optional. Version of the Azure OpenAI service to deploy. Defaults to 2025-01-01-preview.') +param azureopenaiVersion string = '2024-12-01-preview' -param solutionPrefix string = 'macae-${padLeft(take(toLower(uniqueString(subscription().id, environmentName, resourceGroup().location, resourceGroup().name)), 12), 12, '0')}' +@minLength(1) +@allowed([ + 'Standard' + 'GlobalStandard' +]) +@description('Optional. GPT model deployment type. Defaults to GlobalStandard.') +param gptModelDeploymentType string = 'GlobalStandard' + +@minLength(1) +@allowed([ + 'Standard' + 'GlobalStandard' +]) +@description('Optional. GPT model deployment type. Defaults to GlobalStandard.') +param gptReasoningModelDeploymentType string = 'GlobalStandard' + +@description('Optional. AI model deployment token capacity. Defaults to 250 for optimal performance.') +param gptModelCapacity int = 50 + +@description('Optional. AI model deployment token capacity. Defaults to 150 for optimal performance.') +param gptReasoningModelCapacity int = 50 @description('Optional. The tags to apply to all deployed Azure resources.') -param tags object = { - app: solutionPrefix - location: solutionLocation -} +param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = {} -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource.') -param logAnalyticsWorkspaceConfiguration logAnalyticsWorkspaceConfigurationType = { - enabled: true - name: 'log-${solutionPrefix}' - location: solutionLocation - sku: 'PerGB2018' - tags: tags - dataRetentionInDays: useWafAlignedArchitecture ? 365 : 30 - existingWorkspaceResourceId: existingLogAnalyticsWorkspaceId -} +@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') +param enableMonitoring bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Application Insights resource.') -param applicationInsightsConfiguration applicationInsightsConfigurationType = { - enabled: true - name: 'appi-${solutionPrefix}' - location: solutionLocation - tags: tags - retentionInDays: useWafAlignedArchitecture ? 365 : 30 -} +@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableScalability bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Managed Identity resource.') -param userAssignedManagedIdentityConfiguration userAssignedManagedIdentityType = { - enabled: true - name: 'id-${solutionPrefix}' - location: solutionLocation - tags: tags -} +@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableRedundancy bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the backend subnet.') -param networkSecurityGroupBackendConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-backend-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@description('Optional. Enable private networking for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enablePrivateNetworking bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the containers subnet.') -param networkSecurityGroupContainersConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-containers-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@secure() +@description('Optional. The user name for the administrator account of the virtual machine. Allows to customize credentials if `enablePrivateNetworking` is set to true.') +param virtualMachineAdminUsername string = take(newGuid(), 20) -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the Bastion subnet.') -param networkSecurityGroupBastionConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-bastion-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@description('Optional. The password for the administrator account of the virtual machine. Allows to customize credentials if `enablePrivateNetworking` is set to true.') +@secure() +param virtualMachineAdminPassword string = newGuid() -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the administration subnet.') -param networkSecurityGroupAdministrationConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-administration-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@description('Optional. The Container Registry hostname where the docker images for the backend are located.') +param backendContainerRegistryHostname string = 'biabcontainerreg.azurecr.io' -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine virtual network resource.') -param virtualNetworkConfiguration virtualNetworkConfigurationType = { - enabled: useWafAlignedArchitecture ? true : false - name: 'vnet-${solutionPrefix}' - location: solutionLocation - tags: tags - addressPrefixes: null //Default value set on module configuration - subnets: null //Default value set on module configuration -} +@description('Optional. The Container Image Name to deploy on the backend.') +param backendContainerImageName string = 'macaebackend' -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine bastion resource.') -param bastionConfiguration bastionConfigurationType = { - enabled: true - name: 'bas-${solutionPrefix}' - location: solutionLocation - tags: tags - sku: 'Standard' - virtualNetworkResourceId: null //Default value set on module configuration - publicIpResourceName: 'pip-bas${solutionPrefix}' -} +@description('Optional. The Container Image Tag to deploy on the backend.') +param backendContainerImageTag string = 'latest_2025-07-22_895' -@description('Optional. Configuration for the Windows virtual machine.') -param virtualMachineConfiguration virtualMachineConfigurationType = { - enabled: true - name: 'vm${solutionPrefix}' - location: solutionLocation - tags: tags - adminUsername: 'adminuser' - adminPassword: useWafAlignedArchitecture? 'P@ssw0rd1234' : guid(solutionPrefix, subscription().subscriptionId) - vmSize: 'Standard_D2s_v3' - subnetResourceId: null //Default value set on module configuration -} +@description('Optional. The Container Registry hostname where the docker images for the frontend are located.') +param frontendContainerRegistryHostname string = 'biabcontainerreg.azurecr.io' -@description('Optional. The configuration to apply for the AI Foundry AI Services resource.') -param aiFoundryAiServicesConfiguration aiServicesConfigurationType = { - enabled: true - name: 'aisa-${solutionPrefix}' - location: aiDeploymentsLocation - sku: 'S0' - deployments: null //Default value set on module configuration - subnetResourceId: null //Default value set on module configuration - modelCapacity: gptModelCapacity -} +@description('Optional. The Container Image Name to deploy on the frontend.') +param frontendContainerImageName string = 'macaefrontend' -@description('Optional. The configuration to apply for the AI Foundry AI Project resource.') -param aiFoundryAiProjectConfiguration aiProjectConfigurationType = { - enabled: true - name: 'aifp-${solutionPrefix}' - location: aiDeploymentsLocation - sku: 'Basic' - tags: tags -} +@description('Optional. The Container Image Tag to deploy on the frontend.') +param frontendContainerImageTag string = 'latest_2025-07-22_895' -@description('Optional. The configuration to apply for the Cosmos DB Account resource.') -param cosmosDbAccountConfiguration cosmosDbAccountConfigurationType = { - enabled: true - name: 'cosmos-${solutionPrefix}' - location: solutionLocation - tags: tags - subnetResourceId: null //Default value set on module configuration - sqlDatabases: null //Default value set on module configuration -} +@description('Optional. The Container Registry hostname where the docker images for the MCP are located.') +param MCPContainerRegistryHostname string = 'macaemcpacrdk.azurecr.io' -@description('Optional. The configuration to apply for the Container App Environment resource.') -param containerAppEnvironmentConfiguration containerAppEnvironmentConfigurationType = { - enabled: true - name: 'cae-${solutionPrefix}' - location: solutionLocation - tags: tags - subnetResourceId: null //Default value set on module configuration -} +@description('Optional. The Container Image Name to deploy on the MCP.') +param MCPContainerImageName string = 'macae-mac-app' -@description('Optional. The configuration to apply for the Container App resource.') -param containerAppConfiguration containerAppConfigurationType = { - enabled: true - name: 'ca-${solutionPrefix}' - location: solutionLocation - tags: tags - environmentResourceId: null //Default value set on module configuration - concurrentRequests: '100' - containerCpu: '2.0' - containerMemory: '4.0Gi' - containerImageRegistryDomain: 'biabcontainerreg.azurecr.io' - containerImageName: 'macaebackend' - containerImageTag: imageTag - containerName: 'backend' - ingressTargetPort: 8000 - maxReplicas: 1 - minReplicas: 1 -} +@description('Optional. The Container Image Tag to deploy on the MCP.') +param MCPContainerImageTag string = 't9' -@description('Optional. The configuration to apply for the Web Server Farm resource.') -param webServerFarmConfiguration webServerFarmConfigurationType = { - enabled: true - name: 'asp-${solutionPrefix}' - location: solutionLocation - skuName: useWafAlignedArchitecture? 'P1v3' : 'B2' - skuCapacity: useWafAlignedArchitecture ? 3 : 1 - tags: tags -} +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true -@description('Optional. The configuration to apply for the Web Server Farm resource.') -param webSiteConfiguration webSiteConfigurationType = { - enabled: true - name: 'app-${solutionPrefix}' - location: solutionLocation - containerImageRegistryDomain: 'biabcontainerreg.azurecr.io' - containerImageName: 'macaefrontend' - containerImageTag: imageTag - containerName: 'backend' - tags: tags - environmentResourceId: null //Default value set on module configuration -} +@description('Optional. Resource ID of an existing Log Analytics Workspace.') +param existingLogAnalyticsWorkspaceId string = '' + +@description('Optional. Resource ID of an existing Ai Foundry AI Services resource.') +param existingAiFoundryAiProjectResourceId string = '' + +// ============== // +// Variables // +// ============== // + +var solutionSuffix = toLower(trim(replace( + replace( + replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), + ' ', + '' + ), + '*', + '' +))) + +// 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' + centralus: 'eastus2' + eastasia: 'southeastasia' + eastus: 'centralus' + eastus2: 'centralus' + japaneast: 'australiaeast' + northeurope: 'westeurope' + southeastasia: 'eastasia' + uksouth: 'westeurope' + westeurope: 'northeurope' +} +// Paired location calculated based on 'location' parameter. This location will be used by applicable resources if `enableScalability` is set to `true` +var cosmosDbHaLocation = cosmosDbZoneRedundantHaRegionPairs[location] + +// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. +var replicaRegionPairs = { + australiaeast: 'australiasoutheast' + centralus: 'westus' + eastasia: 'japaneast' + eastus: 'centralus' + eastus2: 'centralus' + japaneast: 'eastasia' + northeurope: 'westeurope' + southeastasia: 'eastasia' + uksouth: 'westeurope' + westeurope: 'northeurope' +} +var replicaLocation = replicaRegionPairs[location] + +// ============== // +// Resources // +// ============== // + + +var allTags = union( + { + 'azd-env-name': solutionName + }, + tags +) +@description('Optional created by user name') +param createdBy string = empty(deployer().userPrincipalName) ? '' : split(deployer().userPrincipalName, '@')[0] -// ========== Resource Group Tag ========== // resource resourceGroupTags 'Microsoft.Resources/tags@2021-04-01' = { name: 'default' properties: { tags: { - ...tags - TemplateName: 'Macae' + ...allTags + TemplateName: 'MACAE' + CreatedBy: createdBy + } + } +} + + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.sa-multiagentcustauteng.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } } } } +// Extracts subscription, resource group, and workspace name from the resource ID when using an existing Log Analytics workspace +var useExistingLogAnalytics = !empty(existingLogAnalyticsWorkspaceId) + +var existingLawSubscription = useExistingLogAnalytics ? split(existingLogAnalyticsWorkspaceId, '/')[2] : '' +var existingLawResourceGroup = useExistingLogAnalytics ? split(existingLogAnalyticsWorkspaceId, '/')[4] : '' +var existingLawName = useExistingLogAnalytics ? split(existingLogAnalyticsWorkspaceId, '/')[8] : '' + +resource existingLogAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2020-08-01' existing = if (useExistingLogAnalytics) { + name: existingLawName + scope: resourceGroup(existingLawSubscription, existingLawResourceGroup) +} + // ========== Log Analytics Workspace ========== // // WAF best practices for Log Analytics: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-log-analytics -// Log Analytics configuration defaults -var logAnalyticsWorkspaceEnabled = logAnalyticsWorkspaceConfiguration.?enabled ?? true -var logAnalyticsWorkspaceResourceName = logAnalyticsWorkspaceConfiguration.?name ?? 'log-${solutionPrefix}' -var existingWorkspaceResourceId = logAnalyticsWorkspaceConfiguration.?existingWorkspaceResourceId ?? '' -var useExistingWorkspace = existingWorkspaceResourceId != '' - -module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.11.2' = if (logAnalyticsWorkspaceEnabled && !useExistingWorkspace) { +// WAF PSRules for Log Analytics: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#azure-monitor-logs +var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' +module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.12.0' = if (enableMonitoring && !useExistingLogAnalytics) { name: take('avm.res.operational-insights.workspace.${logAnalyticsWorkspaceResourceName}', 64) params: { name: logAnalyticsWorkspaceResourceName - tags: logAnalyticsWorkspaceConfiguration.?tags ?? tags - location: logAnalyticsWorkspaceConfiguration.?location ?? solutionLocation + tags: tags + location: location enableTelemetry: enableTelemetry - skuName: logAnalyticsWorkspaceConfiguration.?sku ?? 'PerGB2018' - dataRetention: logAnalyticsWorkspaceConfiguration.?dataRetentionInDays ?? 365 + skuName: 'PerGB2018' + dataRetention: 365 + features: { enableLogAccessUsingOnlyResourcePermissions: true } diagnosticSettings: [{ useThisWorkspace: true }] + // WAF aligned configuration for Redundancy + dailyQuotaGb: enableRedundancy ? 10 : null //WAF recommendation: 10 GB per day is a good starting point for most workloads + replication: enableRedundancy + ? { + enabled: true + location: replicaLocation + } + : null + // WAF aligned configuration for Private Networking + publicNetworkAccessForIngestion: enablePrivateNetworking ? 'Disabled' : 'Enabled' + publicNetworkAccessForQuery: enablePrivateNetworking ? 'Disabled' : 'Enabled' + dataSources: enablePrivateNetworking + ? [ + { + tags: tags + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + ] + : null } } - -var logAnalyticsWorkspaceId = useExistingWorkspace ? existingWorkspaceResourceId : logAnalyticsWorkspace.outputs.resourceId +// Log Analytics Name, workspace ID, customer ID, and shared key (existing or new) +var logAnalyticsWorkspaceName = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.name + : logAnalyticsWorkspace!.outputs.name +var logAnalyticsWorkspaceResourceId = useExistingLogAnalytics + ? existingLogAnalyticsWorkspaceId + : logAnalyticsWorkspace!.outputs.resourceId +var logAnalyticsPrimarySharedKey = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.listKeys().primarySharedKey + : logAnalyticsWorkspace!.outputs!.primarySharedKey +var logAnalyticsWorkspaceId = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.properties.customerId + : logAnalyticsWorkspace!.outputs.logAnalyticsWorkspaceId // ========== Application Insights ========== // // WAF best practices for Application Insights: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/application-insights -// Application Insights configuration defaults -var applicationInsightsEnabled = applicationInsightsConfiguration.?enabled ?? true -var applicationInsightsResourceName = applicationInsightsConfiguration.?name ?? 'appi-${solutionPrefix}' -module applicationInsights 'br/public:avm/res/insights/component:0.6.0' = if (applicationInsightsEnabled) { +// WAF PSRules for Application Insights: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#application-insights +var applicationInsightsResourceName = 'appi-${solutionSuffix}' +module applicationInsights 'br/public:avm/res/insights/component:0.6.0' = if (enableMonitoring) { name: take('avm.res.insights.component.${applicationInsightsResourceName}', 64) params: { name: applicationInsightsResourceName - workspaceResourceId: logAnalyticsWorkspaceId - location: applicationInsightsConfiguration.?location ?? solutionLocation + tags: tags + location: location enableTelemetry: enableTelemetry - tags: applicationInsightsConfiguration.?tags ?? tags - retentionInDays: applicationInsightsConfiguration.?retentionInDays ?? 365 - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + retentionInDays: 365 kind: 'web' disableIpMasking: false flowType: 'Bluefield' + // WAF aligned configuration for Monitoring + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspaceResourceId : '' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null } } -// ========== User assigned identity Web Site ========== // +// ========== User Assigned Identity ========== // // WAF best practices for identity and access management: https://learn.microsoft.com/en-us/azure/well-architected/security/identity-access -var userAssignedManagedIdentityEnabled = userAssignedManagedIdentityConfiguration.?enabled ?? true -var userAssignedManagedIdentityResourceName = userAssignedManagedIdentityConfiguration.?name ?? 'id-${solutionPrefix}' -module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.1' = if (userAssignedManagedIdentityEnabled) { - name: take('avm.res.managed-identity.user-assigned-identity.${userAssignedManagedIdentityResourceName}', 64) +var userAssignedIdentityResourceName = 'id-${solutionSuffix}' +module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.1' = { + name: take('avm.res.managed-identity.user-assigned-identity.${userAssignedIdentityResourceName}', 64) params: { - name: userAssignedManagedIdentityResourceName - tags: userAssignedManagedIdentityConfiguration.?tags ?? tags - location: userAssignedManagedIdentityConfiguration.?location ?? solutionLocation + name: userAssignedIdentityResourceName + location: location + tags: tags enableTelemetry: enableTelemetry } } @@ -311,79 +363,46 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id // ========== Network Security Groups ========== // // WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network // WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking -var networkSecurityGroupBackendEnabled = networkSecurityGroupBackendConfiguration.?enabled ?? true -var networkSecurityGroupBackendResourceName = networkSecurityGroupBackendConfiguration.?name ?? 'nsg-backend-${solutionPrefix}' -module networkSecurityGroupBackend 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupBackendEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupBackendResourceName}', 64) +var networkSecurityGroupBackendResourceName = 'nsg-${solutionSuffix}-backend' +module networkSecurityGroupBackend 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.backend.${networkSecurityGroupBackendResourceName}', 64) params: { name: networkSecurityGroupBackendResourceName - location: networkSecurityGroupBackendConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupBackendConfiguration.?tags ?? tags - enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupBackendConfiguration.?securityRules ?? [ - // { - // name: 'DenySshRdpOutbound' //Azure Bastion - // properties: { - // priority: 200 - // access: 'Deny' - // protocol: '*' - // direction: 'Outbound' - // sourceAddressPrefix: 'VirtualNetwork' - // sourcePortRange: '*' - // destinationAddressPrefix: '*' - // destinationPortRanges: [ - // '3389' - // '22' - // ] - // } - // } - ] - } -} - -var networkSecurityGroupContainersEnabled = networkSecurityGroupContainersConfiguration.?enabled ?? true -var networkSecurityGroupContainersResourceName = networkSecurityGroupContainersConfiguration.?name ?? 'nsg-containers-${solutionPrefix}' -module networkSecurityGroupContainers 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupContainersEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupContainersResourceName}', 64) - params: { - name: networkSecurityGroupContainersResourceName - location: networkSecurityGroupContainersConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupContainersConfiguration.?tags ?? tags + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupContainersConfiguration.?securityRules ?? [ - // { - // name: 'DenySshRdpOutbound' //Azure Bastion - // properties: { - // priority: 200 - // access: 'Deny' - // protocol: '*' - // direction: 'Outbound' - // sourceAddressPrefix: 'VirtualNetwork' - // sourcePortRange: '*' - // destinationAddressPrefix: '*' - // destinationPortRanges: [ - // '3389' - // '22' - // ] - // } - // } + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } ] } } -var networkSecurityGroupBastionEnabled = networkSecurityGroupBastionConfiguration.?enabled ?? true -var networkSecurityGroupBastionResourceName = networkSecurityGroupBastionConfiguration.?name ?? 'nsg-bastion-${solutionPrefix}' -module networkSecurityGroupBastion 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupBastionEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupBastionResourceName}', 64) +var networkSecurityGroupBastionResourceName = 'nsg-${solutionSuffix}-bastion' +module networkSecurityGroupBastion 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.bastion${networkSecurityGroupBastionResourceName}', 64) params: { name: networkSecurityGroupBastionResourceName - location: networkSecurityGroupBastionConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupBastionConfiguration.?tags ?? tags + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupBastionConfiguration.?securityRules ?? [ + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ { name: 'AllowHttpsInBound' properties: { @@ -530,33 +549,92 @@ module networkSecurityGroupBastion 'br/public:avm/res/network/network-security-g } } -var networkSecurityGroupAdministrationEnabled = networkSecurityGroupAdministrationConfiguration.?enabled ?? true -var networkSecurityGroupAdministrationResourceName = networkSecurityGroupAdministrationConfiguration.?name ?? 'nsg-administration-${solutionPrefix}' -module networkSecurityGroupAdministration 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupAdministrationEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupAdministrationResourceName}', 64) +var networkSecurityGroupAdministrationResourceName = 'nsg-${solutionSuffix}-administration' +module networkSecurityGroupAdministration 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.administration.${networkSecurityGroupAdministrationResourceName}', 64) params: { name: networkSecurityGroupAdministrationResourceName - location: networkSecurityGroupAdministrationConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupAdministrationConfiguration.?tags ?? tags + location: location + tags: tags + enableTelemetry: enableTelemetry + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } +} + +var networkSecurityGroupContainersResourceName = 'nsg-${solutionSuffix}-containers' +module networkSecurityGroupContainers 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.containers.${networkSecurityGroupContainersResourceName}', 64) + params: { + name: networkSecurityGroupContainersResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } +} + +var networkSecurityGroupWebsiteResourceName = 'nsg-${solutionSuffix}-website' +module networkSecurityGroupWebsite 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.website.${networkSecurityGroupWebsiteResourceName}', 64) + params: { + name: networkSecurityGroupWebsiteResourceName + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupAdministrationConfiguration.?securityRules ?? [ - // { - // name: 'DenySshRdpOutbound' //Azure Bastion - // properties: { - // priority: 200 - // access: 'Deny' - // protocol: '*' - // direction: 'Outbound' - // sourceAddressPrefix: 'VirtualNetwork' - // sourcePortRange: '*' - // destinationAddressPrefix: '*' - // destinationPortRanges: [ - // '3389' - // '22' - // ] - // } - // } + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } ] } } @@ -564,34 +642,35 @@ module networkSecurityGroupAdministration 'br/public:avm/res/network/network-sec // ========== Virtual Network ========== // // WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network // WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking -var virtualNetworkEnabled = virtualNetworkConfiguration.?enabled ?? true -var virtualNetworkResourceName = virtualNetworkConfiguration.?name ?? 'vnet-${solutionPrefix}' -module virtualNetwork 'br/public:avm/res/network/virtual-network:0.6.1' = if (virtualNetworkEnabled) { +var virtualNetworkResourceName = 'vnet-${solutionSuffix}' +module virtualNetwork 'br/public:avm/res/network/virtual-network:0.7.0' = if (enablePrivateNetworking) { name: take('avm.res.network.virtual-network.${virtualNetworkResourceName}', 64) params: { name: virtualNetworkResourceName - location: virtualNetworkConfiguration.?location ?? solutionLocation - tags: virtualNetworkConfiguration.?tags ?? tags + location: location + tags: tags enableTelemetry: enableTelemetry - addressPrefixes: virtualNetworkConfiguration.?addressPrefixes ?? ['10.0.0.0/8'] - subnets: virtualNetworkConfiguration.?subnets ?? [ + addressPrefixes: ['10.0.0.0/8'] + subnets: [ { name: 'backend' addressPrefix: '10.0.0.0/27' //defaultOutboundAccess: false TODO: check this configuration for a more restricted outbound access - networkSecurityGroupResourceId: networkSecurityGroupBackend.outputs.resourceId + networkSecurityGroupResourceId: networkSecurityGroupBackend!.outputs.resourceId } { name: 'administration' addressPrefix: '10.0.0.32/27' - networkSecurityGroupResourceId: networkSecurityGroupAdministration.outputs.resourceId + networkSecurityGroupResourceId: networkSecurityGroupAdministration!.outputs.resourceId + //defaultOutboundAccess: false TODO: check this configuration for a more restricted outbound access + //natGatewayResourceId: natGateway.outputs.resourceId } { // For Azure Bastion resources deployed on or after November 2, 2021, the minimum AzureBastionSubnet size is /26 or larger (/25, /24, etc.). // https://learn.microsoft.com/en-us/azure/bastion/configuration-settings#subnet name: 'AzureBastionSubnet' //This exact name is required for Azure Bastion addressPrefix: '10.0.0.64/26' - networkSecurityGroupResourceId: networkSecurityGroupBastion.outputs.resourceId + networkSecurityGroupResourceId: networkSecurityGroupBastion!.outputs.resourceId } { // If you use your own vnw, you need to provide a subnet that is dedicated exclusively to the Container App environment you deploy. This subnet isn't available to other services @@ -599,67 +678,221 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:0.6.1' = if (vi name: 'containers' addressPrefix: '10.0.2.0/23' //subnet of size /23 is required for container app delegation: 'Microsoft.App/environments' - networkSecurityGroupResourceId: networkSecurityGroupContainers.outputs.resourceId - privateEndpointNetworkPolicies: 'Disabled' + networkSecurityGroupResourceId: networkSecurityGroupContainers!.outputs.resourceId + privateEndpointNetworkPolicies: 'Enabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + // If you use your own vnw, you need to provide a subnet that is dedicated exclusively to the App Environment you deploy. This subnet isn't available to other services + // https://learn.microsoft.com/en-us/azure/app-service/overview-vnet-integration#subnet-requirements + name: 'webserverfarm' + addressPrefix: '10.0.4.0/27' //When you're creating subnets in Azure portal as part of integrating with the virtual network, a minimum size of /27 is required + delegation: 'Microsoft.Web/serverfarms' + networkSecurityGroupResourceId: networkSecurityGroupWebsite!.outputs.resourceId + privateEndpointNetworkPolicies: 'Enabled' privateLinkServiceNetworkPolicies: 'Enabled' } ] } } -var bastionEnabled = bastionConfiguration.?enabled ?? true -var bastionResourceName = bastionConfiguration.?name ?? 'bas-${solutionPrefix}' +var bastionResourceName = 'bas-${solutionSuffix}' // ========== Bastion host ========== // // WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network // WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking -module bastionHost 'br/public:avm/res/network/bastion-host:0.6.1' = if (virtualNetworkEnabled && bastionEnabled) { +module bastionHost 'br/public:avm/res/network/bastion-host:0.7.0' = if (enablePrivateNetworking) { name: take('avm.res.network.bastion-host.${bastionResourceName}', 64) params: { name: bastionResourceName - location: bastionConfiguration.?location ?? solutionLocation - skuName: bastionConfiguration.?sku ?? 'Standard' + location: location + skuName: 'Standard' enableTelemetry: enableTelemetry - tags: bastionConfiguration.?tags ?? tags - virtualNetworkResourceId: bastionConfiguration.?virtualNetworkResourceId ?? virtualNetwork.?outputs.?resourceId + tags: tags + virtualNetworkResourceId: virtualNetwork!.?outputs.?resourceId publicIPAddressObject: { - name: bastionConfiguration.?publicIpResourceName ?? 'pip-bas${solutionPrefix}' - zones: [] + name: 'pip-bas${solutionSuffix}' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + tags: tags } - disableCopyPaste: false + disableCopyPaste: true enableFileCopy: false - enableIpConnect: true - enableShareableLink: true + enableIpConnect: false + enableShareableLink: false + scaleUnits: 4 + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null } } // ========== Virtual machine ========== // // WAF best practices for virtual machines: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines -var virtualMachineEnabled = virtualMachineConfiguration.?enabled ?? true -var virtualMachineResourceName = virtualMachineConfiguration.?name ?? 'vm${solutionPrefix}' -module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.13.0' = if (virtualNetworkEnabled && virtualMachineEnabled) { - name: take('avm.res.compute.virtual-machine.${virtualMachineResourceName}', 64) +var maintenanceConfigurationResourceName = 'mc-${solutionSuffix}' +module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.3.1' = if (enablePrivateNetworking) { + name: take('avm.res.compute.virtual-machine.${maintenanceConfigurationResourceName}', 64) params: { - name: virtualMachineResourceName - computerName: take(virtualMachineResourceName, 15) - location: virtualMachineConfiguration.?location ?? solutionLocation - tags: virtualMachineConfiguration.?tags ?? tags + name: maintenanceConfigurationResourceName + location: location + tags: tags enableTelemetry: enableTelemetry - vmSize: virtualMachineConfiguration.?vmSize ?? 'Standard_D2s_v3' - adminUsername: virtualMachineConfiguration.?adminUsername ?? 'adminuser' - adminPassword: virtualMachineConfiguration.?adminPassword ?? guid(solutionPrefix, subscription().subscriptionId) - nicConfigurations: [ - { - name: 'nic-${virtualMachineResourceName}' - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - ipConfigurations: [ + extensionProperties: { + InGuestPatchMode: 'User' + } + maintenanceScope: 'InGuestPatch' + maintenanceWindow: { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' + } + visibility: 'Custom' + installPatches: { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + } + } +} + +var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' +var dataCollectionRulesLocation = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.location + : logAnalyticsWorkspace!.outputs.location +module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.6.1' = if (enablePrivateNetworking && enableMonitoring) { + name: take('avm.res.insights.data-collection-rule.${dataCollectionRulesResourceName}', 64) + params: { + name: dataCollectionRulesResourceName + tags: tags + enableTelemetry: enableTelemetry + location: dataCollectionRulesLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + performanceCounters: [ { - name: '${virtualMachineResourceName}-nic01-ipconfig01' - subnetResourceId: virtualMachineConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[1] - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + streams: [ + 'Microsoft-Perf' + ] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' } ] } - ] + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: 'la--1264800308' + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + 'la--1264800308' + ] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + ] + } + } +} + +var proximityPlacementGroupResourceName = 'ppg-${solutionSuffix}' +module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-group:0.4.0' = if (enablePrivateNetworking) { + name: take('avm.res.compute.proximity-placement-group.${proximityPlacementGroupResourceName}', 64) + params: { + name: proximityPlacementGroupResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + availabilityZone: virtualMachineAvailabilityZone + intent: { vmSizes: [virtualMachineSize] } + } +} + +var virtualMachineResourceName = 'vm-${solutionSuffix}' +var virtualMachineAvailabilityZone = 1 +var virtualMachineSize = 'Standard_D2s_v3' +module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.17.0' = if (enablePrivateNetworking) { + name: take('avm.res.compute.virtual-machine.${virtualMachineResourceName}', 64) + params: { + name: virtualMachineResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + computerName: take(virtualMachineResourceName, 15) + osType: 'Windows' + vmSize: virtualMachineSize + adminUsername: virtualMachineAdminUsername + adminPassword: virtualMachineAdminPassword + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId + enableAutomaticUpdates: true + encryptionAtHost: false + availabilityZone: virtualMachineAvailabilityZone + proximityPlacementGroupResourceId: proximityPlacementGroup!.outputs.resourceId imageReference: { publisher: 'microsoft-dsvm' offer: 'dsvm-win-2022' @@ -668,112 +901,240 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.13.0' = if (v } osDisk: { name: 'osdisk-${virtualMachineResourceName}' + caching: 'ReadWrite' createOption: 'FromImage' - managedDisk: { - storageAccountType: 'Standard_LRS' - } + deleteOption: 'Delete' diskSizeGB: 128 - caching: 'ReadWrite' + managedDisk: { storageAccountType: 'Premium_LRS' } } - osType: 'Windows' - encryptionAtHost: false //The property 'securityProfile.encryptionAtHost' is not valid because the 'Microsoft.Compute/EncryptionAtHost' feature is not enabled for this subscription. - zone: 0 + nicConfigurations: [ + { + name: 'nic-${virtualMachineResourceName}' + //networkSecurityGroupResourceId: virtualMachineConfiguration.?nicConfigurationConfiguration.networkSecurityGroupResourceId + //nicSuffix: 'nic-${virtualMachineResourceName}' + tags: tags + deleteOption: 'Delete' + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] + : null + ipConfigurations: [ + { + name: '${virtualMachineResourceName}-nic01-ipconfig01' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[1] + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] + : null + } + ] + } + ] extensionAadJoinConfig: { enabled: true + tags: tags typeHandlerVersion: '1.0' } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: tags + } + //WAF aligned configuration for Monitoring + extensionMonitoringAgentConfig: enableMonitoring + ? { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId + name: 'send-${logAnalyticsWorkspaceName}' + } + ] + enabled: true + tags: tags + } + : null + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: tags + } } } -// ========== AI Foundry: AI Services ========== // -// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai -var openAiSubResource = 'account' -var openAiPrivateDnsZones = { - 'privatelink.cognitiveservices.azure.com': openAiSubResource - 'privatelink.openai.azure.com': openAiSubResource - 'privatelink.services.ai.azure.com': openAiSubResource -} +// ========== Private DNS Zones ========== // +var keyVaultPrivateDNSZone = 'privatelink.${toLower(environment().name) == 'azureusgovernment' ? 'vaultcore.usgovcloudapi.net' : 'vaultcore.azure.net'}' +var privateDnsZones = [ + 'privatelink.cognitiveservices.azure.com' + 'privatelink.openai.azure.com' + 'privatelink.services.ai.azure.com' + 'privatelink.documents.azure.com' + 'privatelink.blob.core.windows.net' + 'privatelink.search.windows.net' + keyVaultPrivateDNSZone +] -module privateDnsZonesAiServices 'br/public:avm/res/network/private-dns-zone:0.7.1' = [ - for zone in objectKeys(openAiPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryAIservicesEnabled) { - name: take( - 'avm.res.network.private-dns-zone.ai-services.${uniqueString(aiFoundryAiServicesResourceName,zone)}.${solutionPrefix}', - 64 - ) +// DNS Zone Index Constants +var dnsZoneIndex = { + cognitiveServices: 0 + openAI: 1 + aiServices: 2 + cosmosDb: 3 + blob: 4 + search: 5 + keyVault: 6 +} + +// List of DNS zone indices that correspond to AI-related services. +var aiRelatedDnsZoneIndices = [ + dnsZoneIndex.cognitiveServices + dnsZoneIndex.openAI + dnsZoneIndex.aiServices +] + +// =================================================== +// DEPLOY PRIVATE DNS ZONES +// - Deploys all zones if no existing Foundry project is used +// - Excludes AI-related zones when using with an existing Foundry project +// =================================================== +@batchSize(5) +module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.7.1' = [ + for (zone, i) in privateDnsZones: if (enablePrivateNetworking && (!useExistingAiFoundryAiProject || !contains( + aiRelatedDnsZoneIndices, + i + ))) { + name: 'avm.res.network.private-dns-zone.${contains(zone, 'azurecontainerapps.io') ? 'containerappenv' : split(zone, '.')[1]}' params: { name: zone tags: tags enableTelemetry: enableTelemetry virtualNetworkLinks: [ { - name: 'vnetlink-${split(zone, '.')[1]}' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId + name: take('vnetlink-${virtualNetworkResourceName}-${split(zone, '.')[1]}', 80) + virtualNetworkResourceId: virtualNetwork!.outputs.resourceId } ] } } ] -// NOTE: Required version 'Microsoft.CognitiveServices/accounts@2024-04-01-preview' not available in AVM -var useExistingFoundryProject = !empty(existingFoundryProjectResourceId) -var existingAiFoundryName = useExistingFoundryProject?split( existingFoundryProjectResourceId,'/')[8]:'' -var aiFoundryAiServicesResourceName = useExistingFoundryProject? existingAiFoundryName : aiFoundryAiServicesConfiguration.?name ?? 'aisa-${solutionPrefix}' -var aiFoundryAIservicesEnabled = aiFoundryAiServicesConfiguration.?enabled ?? true +// ========== AI Foundry: AI Services ========== // +// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai + +var useExistingAiFoundryAiProject = !empty(existingAiFoundryAiProjectResourceId) +var aiFoundryAiServicesResourceGroupName = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[4] + : resourceGroup().name +var aiFoundryAiServicesSubscriptionId = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[2] + : subscription().subscriptionId +var aiFoundryAiServicesResourceName = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[8] + : 'aif-${solutionSuffix}' +var aiFoundryAiProjectResourceName = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[10] + : 'proj-${solutionSuffix}' // AI Project resource id: /subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts//projects/ var aiFoundryAiServicesModelDeployment = { format: 'OpenAI' name: gptModelName version: gptModelVersion sku: { - name: modelDeploymentType - //Curently the capacity is set to 140 for opinanal performance. - capacity: aiFoundryAiServicesConfiguration.?modelCapacity ?? gptModelCapacity + name: gptModelDeploymentType + capacity: gptModelCapacity + } + raiPolicyName: 'Microsoft.Default' +} +var aiFoundryAiServicesReasoningModelDeployment = { + format: 'OpenAI' + name: gptReasoningModelName + version: gptReasoningModelVersion + sku: { + name: gptReasoningModelDeploymentType + capacity: gptReasoningModelCapacity } raiPolicyName: 'Microsoft.Default' } +var aiFoundryAiProjectDescription = 'AI Foundry Project' + +resource existingAiFoundryAiServices 'Microsoft.CognitiveServices/accounts@2025-06-01' existing = if (useExistingAiFoundryAiProject) { + name: aiFoundryAiServicesResourceName + scope: resourceGroup(aiFoundryAiServicesSubscriptionId, aiFoundryAiServicesResourceGroupName) +} -module aiFoundryAiServices 'modules/account/main.bicep' = if (aiFoundryAIservicesEnabled) { +module existingAiFoundryAiServicesDeployments 'modules/ai-services-deployments.bicep' = if (useExistingAiFoundryAiProject) { + name: take('module.ai-services-model-deployments.${existingAiFoundryAiServices.name}', 64) + scope: resourceGroup(aiFoundryAiServicesSubscriptionId, aiFoundryAiServicesResourceGroupName) + params: { + name: existingAiFoundryAiServices.name + deployments: [ + { + name: aiFoundryAiServicesModelDeployment.name + model: { + format: aiFoundryAiServicesModelDeployment.format + name: aiFoundryAiServicesModelDeployment.name + version: aiFoundryAiServicesModelDeployment.version + } + raiPolicyName: aiFoundryAiServicesModelDeployment.raiPolicyName + sku: { + name: aiFoundryAiServicesModelDeployment.sku.name + capacity: aiFoundryAiServicesModelDeployment.sku.capacity + } + } + { + name: aiFoundryAiServicesReasoningModelDeployment.name + model: { + format: aiFoundryAiServicesReasoningModelDeployment.format + name: aiFoundryAiServicesReasoningModelDeployment.name + version: aiFoundryAiServicesReasoningModelDeployment.version + } + raiPolicyName: aiFoundryAiServicesReasoningModelDeployment.raiPolicyName + sku: { + name: aiFoundryAiServicesReasoningModelDeployment.sku.name + capacity: aiFoundryAiServicesReasoningModelDeployment.sku.capacity + } + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' // Cognitive Services OpenAI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + ] + } +} + +module aiFoundryAiServices 'br:mcr.microsoft.com/bicep/avm/res/cognitive-services/account:0.13.2' = if (!useExistingAiFoundryAiProject) { name: take('avm.res.cognitive-services.account.${aiFoundryAiServicesResourceName}', 64) params: { name: aiFoundryAiServicesResourceName - tags: aiFoundryAiServicesConfiguration.?tags ?? tags - location: aiFoundryAiServicesConfiguration.?location ?? aiDeploymentsLocation - enableTelemetry: enableTelemetry - projectName: 'aifp-${solutionPrefix}' - projectDescription: 'aifp-${solutionPrefix}' - existingFoundryProjectResourceId: existingFoundryProjectResourceId - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - sku: aiFoundryAiServicesConfiguration.?sku ?? 'S0' + location: azureAiServiceLocation + tags: tags + sku: 'S0' kind: 'AIServices' - disableLocalAuth: true //Should be set to true for WAF aligned configuration + disableLocalAuth: true + allowProjectManagement: true customSubDomainName: aiFoundryAiServicesResourceName apiProperties: { //staticsEnabled: false } - allowProjectManagement: true - managedIdentities: { - systemAssigned: true - } - publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' - networkAcls: { - bypass: 'AzureServices' - defaultAction: (virtualNetworkEnabled) ? 'Deny' : 'Allow' - } - privateEndpoints: virtualNetworkEnabled && !useExistingFoundryProject - ? ([ - { - name: 'pep-${aiFoundryAiServicesResourceName}' - customNetworkInterfaceName: 'nic-${aiFoundryAiServicesResourceName}' - subnetResourceId: aiFoundryAiServicesConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: map(objectKeys(openAiPrivateDnsZones), zone => { - name: replace(zone, '.', '-') - privateDnsZoneResourceId: resourceId('Microsoft.Network/privateDnsZones', zone) - }) - } - } - ]) - : [] - deployments: aiFoundryAiServicesConfiguration.?deployments ?? [ + deployments: [ { name: aiFoundryAiServicesModelDeployment.name model: { @@ -787,115 +1148,128 @@ module aiFoundryAiServices 'modules/account/main.bicep' = if (aiFoundryAIservice capacity: aiFoundryAiServicesModelDeployment.sku.capacity } } + { + name: aiFoundryAiServicesReasoningModelDeployment.name + model: { + format: aiFoundryAiServicesReasoningModelDeployment.format + name: aiFoundryAiServicesReasoningModelDeployment.name + version: aiFoundryAiServicesReasoningModelDeployment.version + } + raiPolicyName: aiFoundryAiServicesReasoningModelDeployment.raiPolicyName + sku: { + name: aiFoundryAiServicesReasoningModelDeployment.sku.name + capacity: aiFoundryAiServicesReasoningModelDeployment.sku.capacity + } + } ] + networkAcls: { + defaultAction: 'Allow' + virtualNetworkRules: [] + ipRules: [] + } + managedIdentities: { userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] } //To create accounts or projects, you must enable a managed identity on your resource + roleAssignments: [ + { + roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' // Cognitive Services OpenAI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User + principalId: deployingUserPrincipalId + principalType: 'User' + } + { + roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer + principalId: deployingUserPrincipalId + principalType: 'User' + } + ] + // WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + privateEndpoints: (enablePrivateNetworking) + ? ([ + { + name: 'pep-${aiFoundryAiServicesResourceName}' + customNetworkInterfaceName: 'nic-${aiFoundryAiServicesResourceName}' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'ai-services-dns-zone-cognitiveservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-openai' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-aiservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId + } + ] + } + } + ]) + : [] } } -// AI Foundry: AI Project -// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai -var existingAiFounryProjectName = useExistingFoundryProject ? last(split( existingFoundryProjectResourceId,'/')) : '' -var aiFoundryAiProjectName = useExistingFoundryProject ? existingAiFounryProjectName : aiFoundryAiProjectConfiguration.?name ?? 'aifp-${solutionPrefix}' - -var useExistingResourceId = !empty(existingFoundryProjectResourceId) - -module cogServiceRoleAssignmentsNew './modules/role.bicep' = if(!useExistingResourceId) { - params: { - name: 'new-${guid(containerApp.name, aiFoundryAiServices.outputs.resourceId)}' - principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - aiServiceName: aiFoundryAiServices.outputs.name - } - scope: resourceGroup(subscription().subscriptionId, resourceGroup().name) -} - -module cogServiceRoleAssignmentsExisting './modules/role.bicep' = if(useExistingResourceId) { - params: { - name: 'reuse-${guid(containerApp.name, aiFoundryAiServices.outputs.aiProjectInfo.resourceId)}' - principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - aiServiceName: aiFoundryAiServices.outputs.name - } - scope: resourceGroup( split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4]) +resource existingAiFoundryAiServicesProject 'Microsoft.CognitiveServices/accounts/projects@2025-06-01' existing = if (useExistingAiFoundryAiProject) { + name: aiFoundryAiProjectResourceName + parent: existingAiFoundryAiServices } -// User Role Assignment for Azure OpenAI - New Resources -module userOpenAiRoleAssignment './modules/role.bicep' = if (aiFoundryAIservicesEnabled && !useExistingResourceId) { - name: take('user-openai-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}', 64) +module aiFoundryAiServicesProject 'modules/ai-project.bicep' = if (!useExistingAiFoundryAiProject) { + name: take('module.ai-project.${aiFoundryAiProjectResourceName}', 64) params: { - name: 'user-openai-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}' - principalId: deployingUserPrincipalId - aiServiceName: aiFoundryAiServices.outputs.name - principalType: 'User' + name: aiFoundryAiProjectResourceName + location: azureAiServiceLocation + tags: tags + desc: aiFoundryAiProjectDescription + //Implicit dependencies below + aiServicesName: aiFoundryAiServices!.outputs.name } - scope: resourceGroup(subscription().subscriptionId, resourceGroup().name) - dependsOn: [ - aiFoundryAiServices - ] } -// User Role Assignment for Azure OpenAI - Existing Resources -module userOpenAiRoleAssignmentExisting './modules/role.bicep' = if (aiFoundryAIservicesEnabled && useExistingResourceId) { - name: take('user-openai-existing-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}', 64) - params: { - name: 'user-openai-existing-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}' - principalId: deployingUserPrincipalId - aiServiceName: aiFoundryAiServices.outputs.name - principalType: 'User' - } - scope: resourceGroup(split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4]) - dependsOn: [ - aiFoundryAiServices - ] -} +var aiFoundryAiProjectName = useExistingAiFoundryAiProject + ? existingAiFoundryAiServicesProject.name + : aiFoundryAiServicesProject!.outputs.name +var aiFoundryAiProjectEndpoint = useExistingAiFoundryAiProject + ? existingAiFoundryAiServicesProject!.properties.endpoints['AI Foundry API'] + : aiFoundryAiServicesProject!.outputs.apiEndpoint +var aiFoundryAiProjectPrincipalId = useExistingAiFoundryAiProject + ? existingAiFoundryAiServicesProject!.identity.principalId + : aiFoundryAiServicesProject!.outputs.principalId // ========== Cosmos DB ========== // // WAF best practices for Cosmos DB: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/cosmos-db -module privateDnsZonesCosmosDb 'br/public:avm/res/network/private-dns-zone:0.7.0' = if (virtualNetworkEnabled) { - name: take('avm.res.network.private-dns-zone.cosmos-db.${solutionPrefix}', 64) - params: { - name: 'privatelink.documents.azure.com' - enableTelemetry: enableTelemetry - virtualNetworkLinks: [ - { - name: 'vnetlink-cosmosdb' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId - } - ] - tags: tags - } -} -var cosmosDbAccountEnabled = cosmosDbAccountConfiguration.?enabled ?? true -var cosmosDbResourceName = cosmosDbAccountConfiguration.?name ?? 'cosmos-${solutionPrefix}' +var cosmosDbResourceName = 'cosmos-${solutionSuffix}' var cosmosDbDatabaseName = 'macae' var cosmosDbDatabaseMemoryContainerName = 'memory' -module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (cosmosDbAccountEnabled) { + +//TODO: update to latest version of AVM module +module cosmosDb 'br/public:avm/res/document-db/database-account:0.15.0' = { name: take('avm.res.document-db.database-account.${cosmosDbResourceName}', 64) params: { // Required parameters - name: cosmosDbAccountConfiguration.?name ?? 'cosmos-${solutionPrefix}' - location: cosmosDbAccountConfiguration.?location ?? solutionLocation - tags: cosmosDbAccountConfiguration.?tags ?? tags + name: cosmosDbResourceName + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - databaseAccountOfferType: 'Standard' - enableFreeTier: false - networkRestrictions: { - networkAclBypass: 'None' - publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' - } - privateEndpoints: virtualNetworkEnabled - ? [ - { - name: 'pep-${cosmosDbResourceName}' - customNetworkInterfaceName: 'nic-${cosmosDbResourceName}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [{ privateDnsZoneResourceId: privateDnsZonesCosmosDb.outputs.resourceId }] - } - service: 'Sql' - subnetResourceId: cosmosDbAccountConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] - } - ] - : [] - sqlDatabases: concat(cosmosDbAccountConfiguration.?sqlDatabases ?? [], [ + sqlDatabases: [ { name: cosmosDbDatabaseName containers: [ @@ -909,94 +1283,149 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (co } ] } - ]) - locations: [ - { - locationName: cosmosDbAccountConfiguration.?location ?? solutionLocation - failoverPriority: 0 - isZoneRedundant: false - } ] - capabilitiesToAdd: [ - 'EnableServerless' - ] - - sqlRoleAssignmentsPrincipalIds: concat( - [containerApp.outputs.?systemAssignedMIPrincipalId], - [deployingUserPrincipalId] - ) - sqlRoleDefinitions: [ + dataPlaneRoleDefinitions: [ { - // Replace this with built-in role definition Cosmos DB Built-in Data Contributor: https://docs.azure.cn/en-us/cosmos-db/nosql/security/reference-data-plane-roles#cosmos-db-built-in-data-contributor - roleType: 'CustomRole' + // Cosmos DB Built-in Data Contributor: https://docs.azure.cn/en-us/cosmos-db/nosql/security/reference-data-plane-roles#cosmos-db-built-in-data-contributor roleName: 'Cosmos DB SQL Data Contributor' - name: 'cosmos-db-sql-data-contributor' - dataAction: [ + dataActions: [ 'Microsoft.DocumentDB/databaseAccounts/readMetadata' 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' ] + assignments: [ + { principalId: userAssignedIdentity.outputs.principalId } + { principalId: deployingUserPrincipalId } + ] } ] + // WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + // WAF aligned configuration for Private Networking + networkRestrictions: { + networkAclBypass: 'None' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + } + privateEndpoints: enablePrivateNetworking + ? [ + { + name: 'pep-${cosmosDbResourceName}' + customNetworkInterfaceName: 'nic-${cosmosDbResourceName}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDb]!.outputs.resourceId } + ] + } + service: 'Sql' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + } + ] + : [] + // WAF aligned configuration for Redundancy + zoneRedundant: enableRedundancy ? true : false + capabilitiesToAdd: enableRedundancy ? null : ['EnableServerless'] + automaticFailover: enableRedundancy ? true : false + failoverLocations: enableRedundancy + ? [ + { + failoverPriority: 0 + isZoneRedundant: true + locationName: location + } + { + failoverPriority: 1 + isZoneRedundant: true + locationName: cosmosDbHaLocation + } + ] + : [ + { + locationName: location + failoverPriority: 0 + } + ] } } // ========== Backend Container App Environment ========== // // WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps -var containerAppEnvironmentEnabled = containerAppEnvironmentConfiguration.?enabled ?? true -var containerAppEnvironmentResourceName = containerAppEnvironmentConfiguration.?name ?? 'cae-${solutionPrefix}' -module containerAppEnvironment 'modules/container-app-environment.bicep' = if (containerAppEnvironmentEnabled) { - name: take('module.container-app-environment.${containerAppEnvironmentResourceName}', 64) +// PSRule for Container App: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#container-app +var containerAppEnvironmentResourceName = 'cae-${solutionSuffix}' +module containerAppEnvironment 'br/public:avm/res/app/managed-environment:0.11.2' = { + name: take('avm.res.app.managed-environment.${containerAppEnvironmentResourceName}', 64) params: { name: containerAppEnvironmentResourceName - tags: containerAppEnvironmentConfiguration.?tags ?? tags - location: containerAppEnvironmentConfiguration.?location ?? solutionLocation - logAnalyticsResourceId: logAnalyticsWorkspaceId - publicNetworkAccess: 'Enabled' - zoneRedundant: false - applicationInsightsConnectionString: applicationInsights.outputs.connectionString + location: location + tags: tags enableTelemetry: enableTelemetry - subnetResourceId: virtualNetworkEnabled - ? containerAppEnvironmentConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[3] ?? '' - : '' + // WAF aligned configuration for Private Networking + publicNetworkAccess: 'Enabled' // Always enabling the publicNetworkAccess for Container App Environment + internal: false // Must be false when publicNetworkAccess is'Enabled' + infrastructureSubnetResourceId: enablePrivateNetworking ? virtualNetwork.?outputs.?subnetResourceIds[3] : null + // WAF aligned configuration for Monitoring + appLogsConfiguration: enableMonitoring + ? { + destination: 'log-analytics' + logAnalyticsConfiguration: { + customerId: logAnalyticsWorkspaceId + sharedKey: logAnalyticsPrimarySharedKey + } + } + : null + appInsightsConnectionString: enableMonitoring ? applicationInsights!.outputs.connectionString : null + // WAF aligned configuration for Redundancy + zoneRedundant: enableRedundancy ? true : false + infrastructureResourceGroupName: enableRedundancy ? '${resourceGroup().name}-infra' : null + workloadProfiles: enableRedundancy + ? [ + { + maximumCount: 3 + minimumCount: 3 + name: 'CAW01' + workloadProfileType: 'D4' + } + ] + : [ + { + name: 'Consumption' + workloadProfileType: 'Consumption' + } + ] } } // ========== Backend Container App Service ========== // // WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps -var containerAppEnabled = containerAppConfiguration.?enabled ?? true -var containerAppResourceName = containerAppConfiguration.?name ?? 'ca-${solutionPrefix}' -module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (containerAppEnabled) { +// PSRule for Container App: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#container-app +var containerAppResourceName = 'ca-${solutionSuffix}' +module containerApp 'br/public:avm/res/app/container-app:0.18.1' = { name: take('avm.res.app.container-app.${containerAppResourceName}', 64) params: { name: containerAppResourceName - tags: containerAppConfiguration.?tags ?? tags - location: containerAppConfiguration.?location ?? solutionLocation + tags: tags + location: location enableTelemetry: enableTelemetry - environmentResourceId: containerAppConfiguration.?environmentResourceId ?? containerAppEnvironment.outputs.resourceId - managedIdentities: { - systemAssigned: true //Replace with user assigned identity - userAssignedResourceIds: [userAssignedIdentity.outputs.resourceId] - } - ingressTargetPort: containerAppConfiguration.?ingressTargetPort ?? 8000 + environmentResourceId: containerAppEnvironment.outputs.resourceId + managedIdentities: { userAssignedResourceIds: [userAssignedIdentity.outputs.resourceId] } + ingressTargetPort: 8000 ingressExternal: true activeRevisionsMode: 'Single' corsPolicy: { allowedOrigins: [ - 'https://${webSiteName}.azurewebsites.net' - 'http://${webSiteName}.azurewebsites.net' + 'https://${webSiteResourceName}.azurewebsites.net' + 'http://${webSiteResourceName}.azurewebsites.net' ] } + // WAF aligned configuration for Scalability scaleSettings: { - //TODO: Make maxReplicas and minReplicas parameterized - maxReplicas: containerAppConfiguration.?maxReplicas ?? 1 - minReplicas: containerAppConfiguration.?minReplicas ?? 1 + maxReplicas: enableScalability ? 3 : 1 + minReplicas: enableScalability ? 2 : 1 rules: [ { name: 'http-scaler' http: { metadata: { - concurrentRequests: containerAppConfiguration.?concurrentRequests ?? '100' + concurrentRequests: '100' } } } @@ -1004,12 +1433,29 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container } containers: [ { - name: containerAppConfiguration.?containerName ?? 'backend' - image: '${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}' + name: 'backend' + image: '${backendContainerRegistryHostname}/${backendContainerImageName}:${backendContainerImageTag}' + //TODO: configure probes for container app + // probes: [ + // { + // httpGet: { + // httpHeaders: [ + // { + // name: 'Custom-Header' + // value: 'Awesome' + // } + // ] + // path: '/health' + // port: 8080 + // } + // initialDelaySeconds: 3 + // periodSeconds: 3 + // type: 'Liveness' + // } + // ] resources: { - //TODO: Make cpu and memory parameterized - cpu: containerAppConfiguration.?containerCpu ?? '2.0' - memory: containerAppConfiguration.?containerMemory ?? '4.0Gi' + cpu: '2.0' + memory: '4.0Gi' } env: [ { @@ -1042,11 +1488,11 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container } { name: 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY' - value: applicationInsights.outputs.instrumentationKey + value: enableMonitoring ? applicationInsights!.outputs.instrumentationKey : '' } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: applicationInsights.outputs.connectionString + value: enableMonitoring ? applicationInsights!.outputs.connectionString : '' } { name: 'AZURE_AI_SUBSCRIPTION_ID' @@ -1062,11 +1508,11 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container } { name: 'FRONTEND_SITE_NAME' - value: 'https://${webSiteName}.azurewebsites.net' + value: 'https://${webSiteResourceName}.azurewebsites.net' } { name: 'AZURE_AI_AGENT_ENDPOINT' - value: aiFoundryAiServices.outputs.aiProjectInfo.apiEndpoint + value: aiFoundryAiProjectEndpoint } { name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' @@ -1076,6 +1522,62 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container name: 'APP_ENV' value: 'Prod' } + { + name: 'AZURE_AI_SEARCH_CONNECTION_NAME' + value: searchService.outputs.name + } + { + name: 'AZURE_AI_SEARCH_INDEX_NAME' + value: aiSearchIndexName + } + { + name: 'AZURE_AI_SEARCH_ENDPOINT' + value: searchService.outputs.endpoint + } + { + name: 'AZURE_COGNITIVE_SERVICES' + value: 'https://cognitiveservices.azure.com/.default' + } + { + name: 'AZURE_BING_CONNECTION_NAME' + value: 'binggrnd' + } + { + name: 'BING_CONNECTION_NAME' + value: 'binggrnd' + } + { + name: 'REASONING_MODEL_NAME' + value: aiFoundryAiServicesReasoningModelDeployment.name + } + { + name: 'MCP_SERVER_ENDPOINT' + value: 'https://${containerAppMcp.outputs.fqdn}/mcp' + } + { + name: 'MCP_SERVER_NAME' + value: 'MACAE MCP Server' + } + { + name: 'MCP_SERVER_DESCRIPTION' + value: 'MACAE MCP Server Description' + } + { + name: 'AZURE_TENANT_ID' + value: tenant().tenantId + } + { + name: 'AZURE_CLIENT_ID' + value: userAssignedIdentity!.outputs.clientId + } + { + name: 'SUPPORTED_MODELS' + value: '["o3","o4-mini","gpt-4.1","gpt-4.1-mini"]' + } + { + name: 'AZURE_AI_SEARCH_API_KEY' + secretRef: 'azure-ai-search-api-key' + } { name: 'AZURE_STORAGE_BLOB_URL' value: avmStorageAccount.outputs.serviceEndpoints.blob @@ -1085,51 +1587,55 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container value: storageContainerName } { - name: 'AZURE_SEARCH_ENDPOINT' - value: searchService.outputs.endpoint - } - { - name: 'AZURE_SEARCH_CONNECTION_NAME' - value: aiSearchConnectionName + name: 'AZURE_AI_MODEL_DEPLOYMENT_NAME' + value: aiFoundryAiServicesModelDeployment.name } ] + + } + ] + secrets: [ + { + name: 'azure-ai-search-api-key' + keyVaultUrl: keyvault.outputs.secrets[0].uriWithVersion + identity: userAssignedIdentity.outputs.resourceId } ] } } -var containerAppMcpResourceName = 'ca-mcp-${solutionPrefix}' -module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (containerAppEnabled) { +// ========== MCP Container App Service ========== // +// WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps +// PSRule for Container App: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#container-app +var containerAppMcpResourceName = 'ca-mcp-${solutionSuffix}' +module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = { name: take('avm.res.app.container-app.${containerAppMcpResourceName}', 64) params: { name: containerAppMcpResourceName - tags: containerAppConfiguration.?tags ?? tags - location: containerAppConfiguration.?location ?? solutionLocation + tags: tags + location: location enableTelemetry: enableTelemetry - environmentResourceId: containerAppConfiguration.?environmentResourceId ?? containerAppEnvironment.outputs.resourceId - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] - } + environmentResourceId: containerAppEnvironment.outputs.resourceId + managedIdentities: { userAssignedResourceIds: [userAssignedIdentity.outputs.resourceId] } ingressTargetPort: 9000 ingressExternal: true activeRevisionsMode: 'Single' corsPolicy: { allowedOrigins: [ - 'https://${webSiteName}.azurewebsites.net' - 'http://${webSiteName}.azurewebsites.net' + 'https://${webSiteResourceName}.azurewebsites.net' + 'http://${webSiteResourceName}.azurewebsites.net' ] } // WAF aligned configuration for Scalability scaleSettings: { - maxReplicas: containerAppConfiguration.?maxReplicas ?? 1 - minReplicas: containerAppConfiguration.?minReplicas ?? 1 + maxReplicas: enableScalability ? 3 : 1 + minReplicas: enableScalability ? 2 : 1 rules: [ { name: 'http-scaler' http: { metadata: { - concurrentRequests: containerAppConfiguration.?concurrentRequests ?? '100' + concurrentRequests: '100' } } } @@ -1138,11 +1644,29 @@ module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (contai containers: [ { name: 'mcp' - image: 'macaemcpacrdk.azurecr.io/macae-mac-app:t9' //'${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}' + image: '${MCPContainerRegistryHostname}/${MCPContainerImageName}:${MCPContainerImageTag}' + //image: 'macaemcpacrdk.azurecr.io/macae-mac-app:t9' + //TODO: configure probes for container app + // probes: [ + // { + // httpGet: { + // httpHeaders: [ + // { + // name: 'Custom-Header' + // value: 'Awesome' + // } + // ] + // path: '/health' + // port: 8080 + // } + // initialDelaySeconds: 3 + // periodSeconds: 3 + // type: 'Liveness' + // } + // ] resources: { - //TODO: Make cpu and memory parameterized - cpu: containerAppConfiguration.?containerCpu ?? '2.0' - memory: containerAppConfiguration.?containerMemory ?? '4.0Gi' + cpu: '2.0' + memory: '4.0Gi' } env: [ { @@ -1195,83 +1719,81 @@ module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (contai } } -var webServerFarmEnabled = webServerFarmConfiguration.?enabled ?? true -var webServerFarmResourceName = webServerFarmConfiguration.?name ?? 'asp-${solutionPrefix}' - // ========== Frontend server farm ========== // -// WAF best practices for web app service: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps -module webServerFarm 'br/public:avm/res/web/serverfarm:0.4.1' = if (webServerFarmEnabled) { +// WAF best practices for Web Application Services: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps +// PSRule for Web Server Farm: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#app-service +var webServerFarmResourceName = 'asp-${solutionSuffix}' +module webServerFarm 'br/public:avm/res/web/serverfarm:0.5.0' = { name: take('avm.res.web.serverfarm.${webServerFarmResourceName}', 64) params: { name: webServerFarmResourceName tags: tags - location: webServerFarmConfiguration.?location ?? solutionLocation - skuName: webServerFarmConfiguration.?skuName ?? 'P1v3' - skuCapacity: webServerFarmConfiguration.?skuCapacity ?? 3 + enableTelemetry: enableTelemetry + location: location reserved: true - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] kind: 'linux' - zoneRedundant: false //TODO: make it zone redundant for waf aligned + // WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + // WAF aligned configuration for Scalability + skuName: enableScalability || enableRedundancy ? 'P1v3' : 'B3' + skuCapacity: enableScalability ? 3 : 1 + // WAF aligned configuration for Redundancy + zoneRedundant: enableRedundancy ? true : false } } // ========== Frontend web site ========== // // WAF best practices for web app service: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps -var webSiteEnabled = webSiteConfiguration.?enabled ?? true +// PSRule for Web Server Farm: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#app-service -var webSiteName = 'app-${solutionPrefix}' -module webSite 'br/public:avm/res/web/site:0.15.1' = if (webSiteEnabled) { - name: take('avm.res.web.site.${webSiteName}', 64) +//NOTE: AVM module adds 1 MB of overhead to the template. Keeping vanilla resource to save template size. +var webSiteResourceName = 'app-${solutionSuffix}' +module webSite 'modules/web-sites.bicep' = { + name: take('module.web-sites.${webSiteResourceName}', 64) params: { - name: webSiteName - tags: webSiteConfiguration.?tags ?? tags - location: webSiteConfiguration.?location ?? solutionLocation + name: webSiteResourceName + tags: tags + location: location kind: 'app,linux,container' - enableTelemetry: enableTelemetry - serverFarmResourceId: webSiteConfiguration.?environmentResourceId ?? webServerFarm.?outputs.resourceId - appInsightResourceId: applicationInsights.outputs.resourceId - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - publicNetworkAccess: 'Enabled' //TODO: use Azure Front Door WAF or Application Gateway WAF instead + serverFarmResourceId: webServerFarm.?outputs.resourceId siteConfig: { - linuxFxVersion: 'DOCKER|${webSiteConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${webSiteConfiguration.?containerImageName ?? 'macaefrontend'}:${webSiteConfiguration.?containerImageTag ?? 'latest'}' - } - appSettingsKeyValuePairs: { - SCM_DO_BUILD_DURING_DEPLOYMENT: 'true' - DOCKER_REGISTRY_SERVER_URL: 'https://${webSiteConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}' - WEBSITES_PORT: '3000' - WEBSITES_CONTAINER_START_TIME_LIMIT: '1800' // 30 minutes, adjust as needed - BACKEND_API_URL: 'https://${containerApp.outputs.fqdn}' - AUTH_ENABLED: 'false' - APP_ENV: 'Prod' + linuxFxVersion: 'DOCKER|${frontendContainerRegistryHostname}/${frontendContainerImageName}:${frontendContainerImageTag}' + minTlsVersion: '1.2' } - } -} - - -// ========== Storage Account ========== // - -module privateDnsZonesStorageAccount 'br/public:avm/res/network/private-dns-zone:0.7.0' = if (virtualNetworkEnabled) { - name: take('avm.res.network.private-dns-zone.storage-account.${solutionPrefix}', 64) - params: { - name: 'privatelink.blob.core.windows.net' - enableTelemetry: enableTelemetry - virtualNetworkLinks: [ + configs: [ { - name: 'vnetlink-storage-account' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId + name: 'appsettings' + properties: { + SCM_DO_BUILD_DURING_DEPLOYMENT: 'true' + DOCKER_REGISTRY_SERVER_URL: 'https://${frontendContainerRegistryHostname}' + WEBSITES_PORT: '3000' + WEBSITES_CONTAINER_START_TIME_LIMIT: '1800' // 30 minutes, adjust as needed + BACKEND_API_URL: 'https://${containerApp.outputs.fqdn}' + AUTH_ENABLED: 'false' + } + // WAF aligned configuration for Monitoring + applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null } ] - tags: tags + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + // WAF aligned configuration for Private Networking + vnetRouteAllEnabled: enablePrivateNetworking ? true : false + vnetImagePullEnabled: enablePrivateNetworking ? true : false + virtualNetworkSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.subnetResourceIds[4] : null + publicNetworkAccess: 'Enabled' // Always enabling the public network access for Web App } } -var storageAccountName = replace('st${solutionPrefix}', '-', '') + +// ========== Storage Account ========== // + +var storageAccountName = replace('st${solutionSuffix}', '-', '') param storageContainerName string = 'sample-dataset' module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.20.0' = { name: take('avm.res.storage.storage-account.${storageAccountName}', 64) params: { name: storageAccountName - location: solutionLocation + location: location managedIdentities: { systemAssigned: true } minimumTlsVersion: 'TLS1_2' enableTelemetry: enableTelemetry @@ -1295,25 +1817,26 @@ module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.20.0' = { // WAF aligned networking networkAcls: { bypass: 'AzureServices' - defaultAction: virtualNetworkEnabled ? 'Deny' : 'Allow' + defaultAction: enablePrivateNetworking ? 'Deny' : 'Allow' } allowBlobPublicAccess: false - publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' // Private endpoints for blob - privateEndpoints: virtualNetworkEnabled + privateEndpoints: enablePrivateNetworking ? [ { - name: 'pep-blob-${solutionPrefix}' + name: 'pep-blob-${solutionSuffix}' + customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' privateDnsZoneGroup: { privateDnsZoneGroupConfigs: [ { name: 'storage-dns-zone-group-blob' - privateDnsZoneResourceId: privateDnsZonesStorageAccount.outputs.resourceId + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.blob]!.outputs.resourceId } ] } - subnetResourceId: virtualNetwork.outputs.subnetResourceIds[0] + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] service: 'blob' } ] @@ -1337,24 +1860,10 @@ module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.20.0' = { // ========== Search Service ========== // -module privateDnsZonesSearchService 'br/public:avm/res/network/private-dns-zone:0.7.0' = if (virtualNetworkEnabled) { - name: take('avm.res.network.private-dns-zone.search-service.${solutionPrefix}', 64) - params: { - name: 'privatelink.search.windows.net' - enableTelemetry: enableTelemetry - virtualNetworkLinks: [ - { - name: 'vnetlink-search-service' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId - } - ] - tags: tags - } -} - -var searchServiceName = 'srch-${solutionPrefix}' +var searchServiceName = 'srch-${solutionSuffix}' +var aiSearchIndexName = 'sample-dataset-index' module searchService 'br/public:avm/res/search/search-service:0.11.1' = { - name: take('avm.res.search.search-service.${solutionPrefix}', 64) + name: take('avm.res.search.search-service.${solutionSuffix}', 64) params: { name: searchServiceName authOptions: { @@ -1367,13 +1876,13 @@ module searchService 'br/public:avm/res/search/search-service:0.11.1' = { managedIdentities: { systemAssigned: true } - publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' networkRuleSet: { bypass: 'AzureServices' } partitionCount: 1 replicaCount: 1 - sku: 'standard' + sku: enableScalability ? 'standard' : 'basic' tags: tags roleAssignments: [ { @@ -1386,19 +1895,30 @@ module searchService 'br/public:avm/res/search/search-service:0.11.1' = { roleDefinitionIdOrName: 'Search Index Data Contributor' principalType: 'User' } + { + principalId: aiFoundryAiProjectPrincipalId + roleDefinitionIdOrName: 'Search Index Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: aiFoundryAiProjectPrincipalId + roleDefinitionIdOrName: 'Search Service Contributor' + principalType: 'ServicePrincipal' + } ] - privateEndpoints: virtualNetworkEnabled + privateEndpoints: enablePrivateNetworking ? [ { - name: 'pep-search-${solutionPrefix}' + name: 'pep-search-${solutionSuffix}' + customNetworkInterfaceName: 'nic-search-${solutionSuffix}' privateDnsZoneGroup: { privateDnsZoneGroupConfigs: [ { - privateDnsZoneResourceId: privateDnsZonesSearchService.outputs.resourceId + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.search]!.outputs.resourceId } ] } - subnetResourceId: virtualNetwork.outputs.subnetResourceIds[0] + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] service: 'searchService' } ] @@ -1408,12 +1928,10 @@ module searchService 'br/public:avm/res/search/search-service:0.11.1' = { // ========== Search Service - AI Project Connection ========== // -var aiSearchConnectionName = 'aifp-srch-connection-${solutionPrefix}' -var aifSubscriptionId = useExistingFoundryProject ? split(existingFoundryProjectResourceId, '/')[2] : subscription().subscriptionId -var aifResourceGroup = useExistingFoundryProject ? split(existingFoundryProjectResourceId, '/')[4] : resourceGroup().name -module aiSearchFoundryConnection 'modules/aifp_search_connection.bicep' = if (aiFoundryAIservicesEnabled) { - name: take('aifp-srch-connection.${solutionPrefix}', 64) - scope: resourceGroup(aifSubscriptionId, aifResourceGroup) +var aiSearchConnectionName = 'aifp-srch-connection-${solutionSuffix}' +module aiSearchFoundryConnection 'modules/aifp-connections.bicep' = { + name: take('aifp-srch-connection.${solutionSuffix}', 64) + scope: resourceGroup(aiFoundryAiServicesSubscriptionId, aiFoundryAiServicesResourceGroupName) params: { aiFoundryProjectName: aiFoundryAiProjectName aiFoundryName: aiFoundryAiServicesResourceName @@ -1421,6 +1939,7 @@ module aiSearchFoundryConnection 'modules/aifp_search_connection.bicep' = if (ai searchServiceResourceId: searchService.outputs.resourceId searchServiceLocation: searchService.outputs.location searchServiceName: searchService.outputs.name + searchApiKey: searchService.outputs.primaryKey } dependsOn: [ aiFoundryAiServices @@ -1428,11 +1947,66 @@ module aiSearchFoundryConnection 'modules/aifp_search_connection.bicep' = if (ai } +// ========== KeyVault ========== // +var keyVaultName = 'kv-${solutionSuffix}' +module keyvault 'br/public:avm/res/key-vault/vault:0.12.1' = { + name: take('avm.res.key-vault.vault.${keyVaultName}', 64) + params: { + name: keyVaultName + location: location + tags: tags + sku: enableScalability ? 'premium' : 'standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + networkAcls: { + defaultAction: 'Allow' + } + enableVaultForDeployment: true + enableVaultForDiskEncryption: true + enableVaultForTemplateDeployment: true + enableRbacAuthorization: true + enableSoftDelete: true + softDeleteRetentionInDays: 7 + diagnosticSettings: enableMonitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : [] + // WAF aligned configuration for Private Networking + privateEndpoints: enablePrivateNetworking + ? [ + { + name: 'pep-${keyVaultName}' + customNetworkInterfaceName: 'nic-${keyVaultName}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [{ privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.keyVault]!.outputs.resourceId }] + } + service: 'vault' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + } + ] + : [] + // WAF aligned configuration for Role-based Access Control + roleAssignments: [ + { + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Key Vault Administrator' + } + ] + secrets: [ + { + name: 'AzureAISearchAPIKey' + value: searchService.outputs.primaryKey + } + ] + enableTelemetry: enableTelemetry + } +} + // ============ // // Outputs // // ============ // -// Add your outputs here +@description('The resource group the resources were deployed into.') +output resourceGroupName string = resourceGroup().name @description('The default url of the website to connect to the Multi-Agent Custom Automation Engine solution.') output webSiteDefaultHostname string = webSite.outputs.defaultHostname @@ -1440,623 +2014,9 @@ output webSiteDefaultHostname string = webSite.outputs.defaultHostname output AZURE_STORAGE_BLOB_URL string = avmStorageAccount.outputs.serviceEndpoints.blob output AZURE_STORAGE_ACCOUNT_NAME string = storageAccountName output AZURE_STORAGE_CONTAINER_NAME string = storageContainerName -output AZURE_SEARCH_ENDPOINT string = searchService.outputs.endpoint -output AZURE_SEARCH_NAME string = searchService.outputs.name - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource configuration.') -type logAnalyticsWorkspaceConfigurationType = { - @description('Optional. If the Log Analytics Workspace resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Log Analytics Workspace resource.') - @maxLength(63) - name: string? - - @description('Optional. Location for the Log Analytics Workspace resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to for the Log Analytics Workspace resource.') - tags: object? - - @description('Optional. The SKU for the Log Analytics Workspace resource.') - sku: ('CapacityReservation' | 'Free' | 'LACluster' | 'PerGB2018' | 'PerNode' | 'Premium' | 'Standalone' | 'Standard')? - - @description('Optional. The number of days to retain the data in the Log Analytics Workspace. If empty, it will be set to 365 days.') - @maxValue(730) - dataRetentionInDays: int? - - @description('Optional: Existing Log Analytics Workspace Resource ID') - existingWorkspaceResourceId: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Application Insights resource configuration.') -type applicationInsightsConfigurationType = { - @description('Optional. If the Application Insights resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Application Insights resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Application Insights resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Application Insights resource.') - tags: object? - - @description('Optional. The retention of Application Insights data in days. If empty, Standard will be used.') - retentionInDays: (120 | 180 | 270 | 30 | 365 | 550 | 60 | 730 | 90)? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Application User Assigned Managed Identity resource configuration.') -type userAssignedManagedIdentityType = { - @description('Optional. If the User Assigned Managed Identity resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the User Assigned Managed Identity resource.') - @maxLength(128) - name: string? - - @description('Optional. Location for the User Assigned Managed Identity resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the User Assigned Managed Identity resource.') - tags: object? -} - -@export() -import { securityRuleType } from 'br/public:avm/res/network/network-security-group:0.5.1' -@description('The type for the Multi-Agent Custom Automation Engine Network Security Group resource configuration.') -type networkSecurityGroupConfigurationType = { - @description('Optional. If the Network Security Group resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Network Security Group resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Network Security Group resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Network Security Group resource.') - tags: object? - - @description('Optional. The security rules to set for the Network Security Group resource.') - securityRules: securityRuleType[]? -} - -@export() -@description('The type for the Multi-Agent Custom Automation virtual network resource configuration.') -type virtualNetworkConfigurationType = { - @description('Optional. If the Virtual Network resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Virtual Network resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Virtual Network resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Virtual Network resource.') - tags: object? - - @description('Optional. An array of 1 or more IP Addresses prefixes for the Virtual Network resource.') - addressPrefixes: string[]? - - @description('Optional. An array of 1 or more subnets for the Virtual Network resource.') - subnets: subnetType[]? -} - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' -type subnetType = { - @description('Optional. The Name of the subnet resource.') - name: string - - @description('Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty.') - addressPrefix: string? - - @description('Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty.') - addressPrefixes: string[]? - - @description('Optional. Application gateway IP configurations of virtual network resource.') - applicationGatewayIPConfigurations: object[]? - - @description('Optional. The delegation to enable on the subnet.') - delegation: string? - - @description('Optional. The resource ID of the NAT Gateway to use for the subnet.') - natGatewayResourceId: string? - - @description('Optional. The resource ID of the network security group to assign to the subnet.') - networkSecurityGroupResourceId: string? - - @description('Optional. enable or disable apply network policies on private endpoint in the subnet.') - privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? - - @description('Optional. enable or disable apply network policies on private link service in the subnet.') - privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? - - @description('Optional. Array of role assignments to create.') - roleAssignments: roleAssignmentType[]? - - @description('Optional. The resource ID of the route table to assign to the subnet.') - routeTableResourceId: string? - - @description('Optional. An array of service endpoint policies.') - serviceEndpointPolicies: object[]? - - @description('Optional. The service endpoints to enable on the subnet.') - serviceEndpoints: string[]? - - @description('Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet.') - defaultOutboundAccess: bool? - - @description('Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty.') - sharingScope: ('DelegatedServices' | 'Tenant')? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Bastion resource configuration.') -type bastionConfigurationType = { - @description('Optional. If the Bastion resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Bastion resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Bastion resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Bastion resource.') - tags: object? - - @description('Optional. The SKU for the Bastion resource.') - sku: ('Basic' | 'Developer' | 'Premium' | 'Standard')? - - @description('Optional. The Virtual Network resource id where the Bastion resource should be deployed.') - virtualNetworkResourceId: string? - - @description('Optional. The name of the Public Ip resource created to connect to Bastion.') - publicIpResourceName: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine virtual machine resource configuration.') -type virtualMachineConfigurationType = { - @description('Optional. If the Virtual Machine resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Virtual Machine resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Virtual Machine resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Virtual Machine resource.') - tags: object? - - @description('Optional. Specifies the size for the Virtual Machine resource.') - vmSize: ( - | 'Basic_A0' - | 'Basic_A1' - | 'Basic_A2' - | 'Basic_A3' - | 'Basic_A4' - | 'Standard_A0' - | 'Standard_A1' - | 'Standard_A2' - | 'Standard_A3' - | 'Standard_A4' - | 'Standard_A5' - | 'Standard_A6' - | 'Standard_A7' - | 'Standard_A8' - | 'Standard_A9' - | 'Standard_A10' - | 'Standard_A11' - | 'Standard_A1_v2' - | 'Standard_A2_v2' - | 'Standard_A4_v2' - | 'Standard_A8_v2' - | 'Standard_A2m_v2' - | 'Standard_A4m_v2' - | 'Standard_A8m_v2' - | 'Standard_B1s' - | 'Standard_B1ms' - | 'Standard_B2s' - | 'Standard_B2ms' - | 'Standard_B4ms' - | 'Standard_B8ms' - | 'Standard_D1' - | 'Standard_D2' - | 'Standard_D3' - | 'Standard_D4' - | 'Standard_D11' - | 'Standard_D12' - | 'Standard_D13' - | 'Standard_D14' - | 'Standard_D1_v2' - | 'Standard_D2_v2' - | 'Standard_D3_v2' - | 'Standard_D4_v2' - | 'Standard_D5_v2' - | 'Standard_D2_v3' - | 'Standard_D4_v3' - | 'Standard_D8_v3' - | 'Standard_D16_v3' - | 'Standard_D32_v3' - | 'Standard_D64_v3' - | 'Standard_D2s_v3' - | 'Standard_D4s_v3' - | 'Standard_D8s_v3' - | 'Standard_D16s_v3' - | 'Standard_D32s_v3' - | 'Standard_D64s_v3' - | 'Standard_D11_v2' - | 'Standard_D12_v2' - | 'Standard_D13_v2' - | 'Standard_D14_v2' - | 'Standard_D15_v2' - | 'Standard_DS1' - | 'Standard_DS2' - | 'Standard_DS3' - | 'Standard_DS4' - | 'Standard_DS11' - | 'Standard_DS12' - | 'Standard_DS13' - | 'Standard_DS14' - | 'Standard_DS1_v2' - | 'Standard_DS2_v2' - | 'Standard_DS3_v2' - | 'Standard_DS4_v2' - | 'Standard_DS5_v2' - | 'Standard_DS11_v2' - | 'Standard_DS12_v2' - | 'Standard_DS13_v2' - | 'Standard_DS14_v2' - | 'Standard_DS15_v2' - | 'Standard_DS13-4_v2' - | 'Standard_DS13-2_v2' - | 'Standard_DS14-8_v2' - | 'Standard_DS14-4_v2' - | 'Standard_E2_v3' - | 'Standard_E4_v3' - | 'Standard_E8_v3' - | 'Standard_E16_v3' - | 'Standard_E32_v3' - | 'Standard_E64_v3' - | 'Standard_E2s_v3' - | 'Standard_E4s_v3' - | 'Standard_E8s_v3' - | 'Standard_E16s_v3' - | 'Standard_E32s_v3' - | 'Standard_E64s_v3' - | 'Standard_E32-16_v3' - | 'Standard_E32-8s_v3' - | 'Standard_E64-32s_v3' - | 'Standard_E64-16s_v3' - | 'Standard_F1' - | 'Standard_F2' - | 'Standard_F4' - | 'Standard_F8' - | 'Standard_F16' - | 'Standard_F1s' - | 'Standard_F2s' - | 'Standard_F4s' - | 'Standard_F8s' - | 'Standard_F16s' - | 'Standard_F2s_v2' - | 'Standard_F4s_v2' - | 'Standard_F8s_v2' - | 'Standard_F16s_v2' - | 'Standard_F32s_v2' - | 'Standard_F64s_v2' - | 'Standard_F72s_v2' - | 'Standard_G1' - | 'Standard_G2' - | 'Standard_G3' - | 'Standard_G4' - | 'Standard_G5' - | 'Standard_GS1' - | 'Standard_GS2' - | 'Standard_GS3' - | 'Standard_GS4' - | 'Standard_GS5' - | 'Standard_GS4-8' - | 'Standard_GS4-4' - | 'Standard_GS5-16' - | 'Standard_GS5-8' - | 'Standard_H8' - | 'Standard_H16' - | 'Standard_H8m' - | 'Standard_H16m' - | 'Standard_H16r' - | 'Standard_H16mr' - | 'Standard_L4s' - | 'Standard_L8s' - | 'Standard_L16s' - | 'Standard_L32s' - | 'Standard_M64s' - | 'Standard_M64ms' - | 'Standard_M128s' - | 'Standard_M128ms' - | 'Standard_M64-32ms' - | 'Standard_M64-16ms' - | 'Standard_M128-64ms' - | 'Standard_M128-32ms' - | 'Standard_NC6' - | 'Standard_NC12' - | 'Standard_NC24' - | 'Standard_NC24r' - | 'Standard_NC6s_v2' - | 'Standard_NC12s_v2' - | 'Standard_NC24s_v2' - | 'Standard_NC24rs_v2' - | 'Standard_NC6s_v3' - | 'Standard_NC12s_v3' - | 'Standard_NC24s_v3' - | 'Standard_NC24rs_v3' - | 'Standard_ND6s' - | 'Standard_ND12s' - | 'Standard_ND24s' - | 'Standard_ND24rs' - | 'Standard_NV6' - | 'Standard_NV12' - | 'Standard_NV24')? - - @description('Optional. The username for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module.') - adminUsername: string? - - @description('Optional. The password for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module.') - @secure() - adminPassword: string? - - @description('Optional. The resource ID of the subnet where the Virtual Machine resource should be deployed.') - subnetResourceId: string? -} - -@export() -import { deploymentType } from 'br/public:avm/res/cognitive-services/account:0.10.2' -@description('The type for the Multi-Agent Custom Automation Engine AI Services resource configuration.') -type aiServicesConfigurationType = { - @description('Optional. If the AI Services resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the AI Services resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the AI Services resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the AI Services resource.') - tags: object? - - @description('Optional. The SKU of the AI Services resource. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') - sku: ( - | 'C2' - | 'C3' - | 'C4' - | 'F0' - | 'F1' - | 'S' - | 'S0' - | 'S1' - | 'S10' - | 'S2' - | 'S3' - | 'S4' - | 'S5' - | 'S6' - | 'S7' - | 'S8' - | 'S9')? - - @description('Optional. The resource Id of the subnet where the AI Services private endpoint should be created.') - subnetResourceId: string? - - @description('Optional. The model deployments to set for the AI Services resource.') - deployments: deploymentType[]? - - @description('Optional. The capacity to set for AI Services GTP model.') - modelCapacity: int? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine AI Foundry AI Project resource configuration.') -type aiProjectConfigurationType = { - @description('Optional. If the AI Project resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the AI Project resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the AI Project resource deployment.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The SKU of the AI Project resource.') - sku: ('Basic' | 'Free' | 'Standard' | 'Premium')? - - @description('Optional. The tags to set for the AI Project resource.') - tags: object? -} - -import { sqlDatabaseType } from 'br/public:avm/res/document-db/database-account:0.13.0' -@export() -@description('The type for the Multi-Agent Custom Automation Engine Cosmos DB Account resource configuration.') -type cosmosDbAccountConfigurationType = { - @description('Optional. If the Cosmos DB Account resource should be deployed or not.') - enabled: bool? - @description('Optional. The name of the Cosmos DB Account resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Cosmos DB Account resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Cosmos DB Account resource.') - tags: object? - - @description('Optional. The resource Id of the subnet where the Cosmos DB Account private endpoint should be created.') - subnetResourceId: string? - - @description('Optional. The SQL databases configuration for the Cosmos DB Account resource.') - sqlDatabases: sqlDatabaseType[]? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Container App Environment resource configuration.') -type containerAppEnvironmentConfigurationType = { - @description('Optional. If the Container App Environment resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Container App Environment resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Container App Environment resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Container App Environment resource.') - tags: object? - - @description('Optional. The resource Id of the subnet where the Container App Environment private endpoint should be created.') - subnetResourceId: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Container App resource configuration.') -type containerAppConfigurationType = { - @description('Optional. If the Container App resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Container App resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Container App resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Container App resource.') - tags: object? - - @description('Optional. The resource Id of the Container App Environment where the Container App should be created.') - environmentResourceId: string? - - @description('Optional. The maximum number of replicas of the Container App.') - maxReplicas: int? - - @description('Optional. The minimum number of replicas of the Container App.') - minReplicas: int? - - @description('Optional. The ingress target port of the Container App.') - ingressTargetPort: int? - - @description('Optional. The concurrent requests allowed for the Container App.') - concurrentRequests: string? - - @description('Optional. The name given to the Container App.') - containerName: string? - - @description('Optional. The container registry domain of the container image to be used by the Container App. Default to `biabcontainerreg.azurecr.io`') - containerImageRegistryDomain: string? - - @description('Optional. The name of the container image to be used by the Container App.') - containerImageName: string? - - @description('Optional. The tag of the container image to be used by the Container App.') - containerImageTag: string? - - @description('Optional. The CPU reserved for the Container App. Defaults to 2.0') - containerCpu: string? - - @description('Optional. The Memory reserved for the Container App. Defaults to 4.0Gi') - containerMemory: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Entra ID Application resource configuration.') -type entraIdApplicationConfigurationType = { - @description('Optional. If the Entra ID Application for website authentication should be deployed or not.') - enabled: bool? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Web Server Farm resource configuration.') -type webServerFarmConfigurationType = { - @description('Optional. If the Web Server Farm resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Web Server Farm resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Web Server Farm resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Web Server Farm resource.') - tags: object? - - @description('Optional. The name of th SKU that will determine the tier, size and family for the Web Server Farm resource. This defaults to P1v3 to leverage availability zones.') - skuName: string? - - @description('Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones.') - skuCapacity: int? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Web Site resource configuration.') -type webSiteConfigurationType = { - @description('Optional. If the Web Site resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Web Site resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Web Site resource deployment.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Web Site resource.') - tags: object? - - @description('Optional. The resource Id of the Web Site Environment where the Web Site should be created.') - environmentResourceId: string? - - @description('Optional. The name given to the Container App.') - containerName: string? - - @description('Optional. The container registry domain of the container image to be used by the Web Site. Default to `biabcontainerreg.azurecr.io`') - containerImageRegistryDomain: string? - - @description('Optional. The name of the container image to be used by the Web Site.') - containerImageName: string? - - @description('Optional. The tag of the container image to be used by the Web Site.') - containerImageTag: string? -} - +output AZURE_AI_SEARCH_ENDPOINT string = searchService.outputs.endpoint +output AZURE_AI_SEARCH_NAME string = searchService.outputs.name +output AZURE_AI_SEARCH_INDEX_NAME string = aiSearchIndexName output COSMOSDB_ENDPOINT string = 'https://${cosmosDbResourceName}.documents.azure.com:443/' output COSMOSDB_DATABASE string = cosmosDbDatabaseName @@ -2073,7 +2033,18 @@ output AZURE_AI_PROJECT_NAME string = aiFoundryAiProjectName output AZURE_AI_MODEL_DEPLOYMENT_NAME string = aiFoundryAiServicesModelDeployment.name // output APPLICATIONINSIGHTS_CONNECTION_STRING string = applicationInsights.outputs.connectionString output AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME string = aiFoundryAiServicesModelDeployment.name -output AZURE_AI_AGENT_ENDPOINT string = aiFoundryAiServices.outputs.aiProjectInfo.apiEndpoint +output AZURE_AI_AGENT_ENDPOINT string = aiFoundryAiProjectEndpoint output APP_ENV string = 'Prod' -output AI_FOUNDRY_RESOURCE_ID string = aiFoundryAiServices.outputs.resourceId +output AI_FOUNDRY_RESOURCE_ID string = !useExistingAiFoundryAiProject ? aiFoundryAiServices.outputs.resourceId : existingAiFoundryAiProjectResourceId output COSMOSDB_ACCOUNT_NAME string = cosmosDbResourceName +output AZURE_SEARCH_ENDPOINT string =searchService.outputs.endpoint +output AZURE_CLIENT_ID string = userAssignedIdentity!.outputs.clientId +output AZURE_TENANT_ID string = tenant().tenantId +output AZURE_AI_SEARCH_CONNECTION_NAME string = searchService.outputs.name +output AZURE_COGNITIVE_SERVICES string = 'https://cognitiveservices.azure.com/.default' +output REASONING_MODEL_NAME string = aiFoundryAiServicesReasoningModelDeployment.name +output MCP_SERVER_NAME string = 'MACAE MCP Server' +output MCP_SERVER_DESCRIPTION string = 'MACAE MCP Server Description' +output SUPPORTED_MODELS string = '["o3","o4-mini","gpt-4.1","gpt-4.1-mini"]' +output AZURE_AI_SEARCH_API_KEY string = '' +output BACKEND_URL string = 'https://${containerApp.outputs.fqdn}' diff --git a/infra/main.json b/infra/main.json deleted file mode 100644 index 8d8b352ee..000000000 --- a/infra/main.json +++ /dev/null @@ -1,44311 +0,0 @@ -{ - "$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.1.42791", - "templateHash": "15200952961082687731" - }, - "name": "Multi-Agent Custom Automation Engine", - "description": "This module contains the resources required to deploy the Multi-Agent Custom Automation Engine solution accelerator for both Sandbox environments and WAF aligned environments." - }, - "definitions": { - "logAnalyticsWorkspaceConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Log Analytics Workspace resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 63, - "metadata": { - "description": "Optional. The name of the Log Analytics Workspace resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Log Analytics Workspace resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to for the Log Analytics Workspace resource." - } - }, - "sku": { - "type": "string", - "allowedValues": [ - "CapacityReservation", - "Free", - "LACluster", - "PerGB2018", - "PerNode", - "Premium", - "Standalone", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU for the Log Analytics Workspace resource." - } - }, - "dataRetentionInDays": { - "type": "int", - "nullable": true, - "maxValue": 730, - "metadata": { - "description": "Optional. The number of days to retain the data in the Log Analytics Workspace. If empty, it will be set to 365 days." - } - }, - "existingWorkspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional: Existing Log Analytics Workspace Resource ID" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource configuration." - } - }, - "applicationInsightsConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Application Insights resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 90, - "metadata": { - "description": "Optional. The name of the Application Insights resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Application Insights resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Application Insights resource." - } - }, - "retentionInDays": { - "type": "int", - "allowedValues": [ - 120, - 180, - 270, - 30, - 365, - 550, - 60, - 730, - 90 - ], - "nullable": true, - "metadata": { - "description": "Optional. The retention of Application Insights data in days. If empty, Standard will be used." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Application Insights resource configuration." - } - }, - "userAssignedManagedIdentityType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the User Assigned Managed Identity resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 128, - "metadata": { - "description": "Optional. The name of the User Assigned Managed Identity resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the User Assigned Managed Identity resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the User Assigned Managed Identity resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Application User Assigned Managed Identity resource configuration." - } - }, - "networkSecurityGroupConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Network Security Group resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 90, - "metadata": { - "description": "Optional. The name of the Network Security Group resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Network Security Group resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Network Security Group resource." - } - }, - "securityRules": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The security rules to set for the Network Security Group resource." - } - } - }, - "metadata": { - "description": "The type for the Multi-Agent Custom Automation Engine Network Security Group resource configuration." - } - }, - "virtualNetworkConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Virtual Network resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 90, - "metadata": { - "description": "Optional. The name of the Virtual Network resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Virtual Network resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Virtual Network resource." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of 1 or more IP Addresses prefixes for the Virtual Network resource." - } - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of 1 or more subnets for the Virtual Network resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation virtual network resource configuration." - } - }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Optional. The Name of the subnet resource." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, - "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." - } - } - } - }, - "bastionConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Bastion resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 90, - "metadata": { - "description": "Optional. The name of the Bastion resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Bastion resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Bastion resource." - } - }, - "sku": { - "type": "string", - "allowedValues": [ - "Basic", - "Developer", - "Premium", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU for the Bastion resource." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Virtual Network resource id where the Bastion resource should be deployed." - } - }, - "publicIpResourceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Public Ip resource created to connect to Bastion." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Bastion resource configuration." - } - }, - "virtualMachineConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Virtual Machine resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 90, - "metadata": { - "description": "Optional. The name of the Virtual Machine resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Virtual Machine resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Virtual Machine resource." - } - }, - "vmSize": { - "type": "string", - "allowedValues": [ - "Basic_A0", - "Basic_A1", - "Basic_A2", - "Basic_A3", - "Basic_A4", - "Standard_A0", - "Standard_A1", - "Standard_A10", - "Standard_A11", - "Standard_A1_v2", - "Standard_A2", - "Standard_A2_v2", - "Standard_A2m_v2", - "Standard_A3", - "Standard_A4", - "Standard_A4_v2", - "Standard_A4m_v2", - "Standard_A5", - "Standard_A6", - "Standard_A7", - "Standard_A8", - "Standard_A8_v2", - "Standard_A8m_v2", - "Standard_A9", - "Standard_B1ms", - "Standard_B1s", - "Standard_B2ms", - "Standard_B2s", - "Standard_B4ms", - "Standard_B8ms", - "Standard_D1", - "Standard_D11", - "Standard_D11_v2", - "Standard_D12", - "Standard_D12_v2", - "Standard_D13", - "Standard_D13_v2", - "Standard_D14", - "Standard_D14_v2", - "Standard_D15_v2", - "Standard_D16_v3", - "Standard_D16s_v3", - "Standard_D1_v2", - "Standard_D2", - "Standard_D2_v2", - "Standard_D2_v3", - "Standard_D2s_v3", - "Standard_D3", - "Standard_D32_v3", - "Standard_D32s_v3", - "Standard_D3_v2", - "Standard_D4", - "Standard_D4_v2", - "Standard_D4_v3", - "Standard_D4s_v3", - "Standard_D5_v2", - "Standard_D64_v3", - "Standard_D64s_v3", - "Standard_D8_v3", - "Standard_D8s_v3", - "Standard_DS1", - "Standard_DS11", - "Standard_DS11_v2", - "Standard_DS12", - "Standard_DS12_v2", - "Standard_DS13", - "Standard_DS13-2_v2", - "Standard_DS13-4_v2", - "Standard_DS13_v2", - "Standard_DS14", - "Standard_DS14-4_v2", - "Standard_DS14-8_v2", - "Standard_DS14_v2", - "Standard_DS15_v2", - "Standard_DS1_v2", - "Standard_DS2", - "Standard_DS2_v2", - "Standard_DS3", - "Standard_DS3_v2", - "Standard_DS4", - "Standard_DS4_v2", - "Standard_DS5_v2", - "Standard_E16_v3", - "Standard_E16s_v3", - "Standard_E2_v3", - "Standard_E2s_v3", - "Standard_E32-16_v3", - "Standard_E32-8s_v3", - "Standard_E32_v3", - "Standard_E32s_v3", - "Standard_E4_v3", - "Standard_E4s_v3", - "Standard_E64-16s_v3", - "Standard_E64-32s_v3", - "Standard_E64_v3", - "Standard_E64s_v3", - "Standard_E8_v3", - "Standard_E8s_v3", - "Standard_F1", - "Standard_F16", - "Standard_F16s", - "Standard_F16s_v2", - "Standard_F1s", - "Standard_F2", - "Standard_F2s", - "Standard_F2s_v2", - "Standard_F32s_v2", - "Standard_F4", - "Standard_F4s", - "Standard_F4s_v2", - "Standard_F64s_v2", - "Standard_F72s_v2", - "Standard_F8", - "Standard_F8s", - "Standard_F8s_v2", - "Standard_G1", - "Standard_G2", - "Standard_G3", - "Standard_G4", - "Standard_G5", - "Standard_GS1", - "Standard_GS2", - "Standard_GS3", - "Standard_GS4", - "Standard_GS4-4", - "Standard_GS4-8", - "Standard_GS5", - "Standard_GS5-16", - "Standard_GS5-8", - "Standard_H16", - "Standard_H16m", - "Standard_H16mr", - "Standard_H16r", - "Standard_H8", - "Standard_H8m", - "Standard_L16s", - "Standard_L32s", - "Standard_L4s", - "Standard_L8s", - "Standard_M128-32ms", - "Standard_M128-64ms", - "Standard_M128ms", - "Standard_M128s", - "Standard_M64-16ms", - "Standard_M64-32ms", - "Standard_M64ms", - "Standard_M64s", - "Standard_NC12", - "Standard_NC12s_v2", - "Standard_NC12s_v3", - "Standard_NC24", - "Standard_NC24r", - "Standard_NC24rs_v2", - "Standard_NC24rs_v3", - "Standard_NC24s_v2", - "Standard_NC24s_v3", - "Standard_NC6", - "Standard_NC6s_v2", - "Standard_NC6s_v3", - "Standard_ND12s", - "Standard_ND24rs", - "Standard_ND24s", - "Standard_ND6s", - "Standard_NV12", - "Standard_NV24", - "Standard_NV6" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size for the Virtual Machine resource." - } - }, - "adminUsername": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The username for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module." - } - }, - "adminPassword": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The password for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module." - } - }, - "subnetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the subnet where the Virtual Machine resource should be deployed." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine virtual machine resource configuration." - } - }, - "aiServicesConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the AI Services resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 90, - "metadata": { - "description": "Optional. The name of the AI Services resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the AI Services resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the AI Services resource." - } - }, - "sku": { - "type": "string", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU of the AI Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "subnetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the subnet where the AI Services private endpoint should be created." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The model deployments to set for the AI Services resource." - } - }, - "modelCapacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity to set for AI Services GTP model." - } - } - }, - "metadata": { - "description": "The type for the Multi-Agent Custom Automation Engine AI Services resource configuration." - } - }, - "aiProjectConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the AI Project resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 90, - "metadata": { - "description": "Optional. The name of the AI Project resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the AI Project resource deployment." - } - }, - "sku": { - "type": "string", - "allowedValues": [ - "Basic", - "Free", - "Premium", - "Standard" - ], - "nullable": true, - "metadata": { - "description": "Optional. The SKU of the AI Project resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the AI Project resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine AI Foundry AI Project resource configuration." - } - }, - "cosmosDbAccountConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Cosmos DB Account resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 60, - "metadata": { - "description": "Optional. The name of the Cosmos DB Account resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Cosmos DB Account resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Cosmos DB Account resource." - } - }, - "subnetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the subnet where the Cosmos DB Account private endpoint should be created." - } - }, - "sqlDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlDatabaseType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The SQL databases configuration for the Cosmos DB Account resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Cosmos DB Account resource configuration." - } - }, - "containerAppEnvironmentConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Container App Environment resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 60, - "metadata": { - "description": "Optional. The name of the Container App Environment resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Container App Environment resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Container App Environment resource." - } - }, - "subnetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the subnet where the Container App Environment private endpoint should be created." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Container App Environment resource configuration." - } - }, - "containerAppConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Container App resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 60, - "metadata": { - "description": "Optional. The name of the Container App resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Container App resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Container App resource." - } - }, - "environmentResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the Container App Environment where the Container App should be created." - } - }, - "maxReplicas": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The maximum number of replicas of the Container App." - } - }, - "minReplicas": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The minimum number of replicas of the Container App." - } - }, - "ingressTargetPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The ingress target port of the Container App." - } - }, - "concurrentRequests": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The concurrent requests allowed for the Container App." - } - }, - "containerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name given to the Container App." - } - }, - "containerImageRegistryDomain": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The container registry domain of the container image to be used by the Container App. Default to `biabcontainerreg.azurecr.io`" - } - }, - "containerImageName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container image to be used by the Container App." - } - }, - "containerImageTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tag of the container image to be used by the Container App." - } - }, - "containerCpu": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CPU reserved for the Container App. Defaults to 2.0" - } - }, - "containerMemory": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Memory reserved for the Container App. Defaults to 4.0Gi" - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Container App resource configuration." - } - }, - "entraIdApplicationConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Entra ID Application for website authentication should be deployed or not." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Entra ID Application resource configuration." - } - }, - "webServerFarmConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Web Server Farm resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 60, - "metadata": { - "description": "Optional. The name of the Web Server Farm resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Web Server Farm resource." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Web Server Farm resource." - } - }, - "skuName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of th SKU that will determine the tier, size and family for the Web Server Farm resource. This defaults to P1v3 to leverage availability zones." - } - }, - "skuCapacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Web Server Farm resource configuration." - } - }, - "webSiteConfigurationType": { - "type": "object", - "properties": { - "enabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If the Web Site resource should be deployed or not." - } - }, - "name": { - "type": "string", - "nullable": true, - "maxLength": 60, - "metadata": { - "description": "Optional. The name of the Web Site resource." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "azd": { - "type": "location" - }, - "description": "Optional. Location for the Web Site resource deployment." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The tags to set for the Web Site resource." - } - }, - "environmentResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource Id of the Web Site Environment where the Web Site should be created." - } - }, - "containerName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name given to the Container App." - } - }, - "containerImageRegistryDomain": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The container registry domain of the container image to be used by the Web Site. Default to `biabcontainerreg.azurecr.io`" - } - }, - "containerImageName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container image to be used by the Web Site." - } - }, - "containerImageTag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tag of the container image to be used by the Web Site." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the Multi-Agent Custom Automation Engine Web Site resource configuration." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "description": "The type for a cognitive services account deployment.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/cognitive-services/account:0.10.2" - } - } - }, - "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.5.1" - } - } - }, - "securityRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "metadata": { - "description": "Required. The properties of the security rule." - } - } - }, - "metadata": { - "description": "The type of a security rule.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/network/network-security-group:0.5.1" - } - } - }, - "sqlDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "containers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "properties": { - "conflictResolutionPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The conflict resolution path in the case of LastWriterWins mode. Required if `mode` is set to 'LastWriterWins'." - } - }, - "conflictResolutionProcedure": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The procedure to resolve conflicts in the case of custom mode. Required if `mode` is set to 'Custom'." - } - }, - "mode": { - "type": "string", - "allowedValues": [ - "Custom", - "LastWriterWins" - ], - "metadata": { - "description": "Required. Indicates the conflict resolution mode." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - } - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "indexingPolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Indexing policy of the container." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used." - } - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "items": { - "type": "object", - "properties": { - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. List of paths must be unique for each document in the Azure Cosmos DB service." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - } - }, - "metadata": { - "description": "The type for the SQL database.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/document-db/database-account:0.13.0" - } - } - } - }, - "parameters": { - "useWafAlignedArchitecture": { - "type": "bool", - "metadata": { - "description": "Set to true if you want to deploy WAF-aligned infrastructure." - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Use this parameter to use an existing AI project resource ID" - } - }, - "environmentName": { - "type": "string", - "metadata": { - "description": "Required. Name of the environment to deploy the solution into." - } - }, - "solutionLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. Location for all Resources except AI Foundry." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "existingLogAnalyticsWorkspaceId": { - "type": "string", - "defaultValue": "" - }, - "azureopenaiVersion": { - "type": "string", - "defaultValue": "2025-01-01-preview" - }, - "aiDeploymentsLocation": { - "type": "string", - "allowedValues": [ - "australiaeast", - "eastus2", - "francecentral", - "japaneast", - "norwayeast", - "swedencentral", - "uksouth", - "westus" - ], - "metadata": { - "azd": { - "type": "location", - "usageName": [ - "OpenAI.GlobalStandard.gpt-4o, 150" - ] - }, - "description": "Azure OpenAI Location" - } - }, - "gptModelName": { - "type": "string", - "defaultValue": "gpt-4o", - "minLength": 1, - "metadata": { - "description": "Name of the GPT model to deploy:" - } - }, - "gptModelVersion": { - "type": "string", - "defaultValue": "2024-08-06" - }, - "modelDeploymentType": { - "type": "string", - "defaultValue": "GlobalStandard", - "minLength": 1, - "metadata": { - "description": "GPT model deployment type:" - } - }, - "gptModelCapacity": { - "type": "int", - "defaultValue": 150, - "metadata": { - "description": "Optional. AI model deployment token capacity." - } - }, - "imageTag": { - "type": "string", - "defaultValue": "latest", - "metadata": { - "description": "Set the image tag for the container images used in the solution. Default is \"latest\"." - } - }, - "solutionPrefix": { - "type": "string", - "defaultValue": "[format('macae-{0}', padLeft(take(toLower(uniqueString(subscription().id, parameters('environmentName'), resourceGroup().location, resourceGroup().name)), 12), 12, '0'))]" - }, - "tags": { - "type": "object", - "defaultValue": { - "app": "[parameters('solutionPrefix')]", - "location": "[parameters('solutionLocation')]" - }, - "metadata": { - "description": "Optional. The tags to apply to all deployed Azure resources." - } - }, - "logAnalyticsWorkspaceConfiguration": { - "$ref": "#/definitions/logAnalyticsWorkspaceConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('log-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "sku": "PerGB2018", - "tags": "[parameters('tags')]", - "dataRetentionInDays": "[if(parameters('useWafAlignedArchitecture'), 365, 30)]", - "existingWorkspaceResourceId": "[parameters('existingLogAnalyticsWorkspaceId')]" - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource." - } - }, - "applicationInsightsConfiguration": { - "$ref": "#/definitions/applicationInsightsConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('appi-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "retentionInDays": "[if(parameters('useWafAlignedArchitecture'), 365, 30)]" - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Application Insights resource." - } - }, - "userAssignedManagedIdentityConfiguration": { - "$ref": "#/definitions/userAssignedManagedIdentityType", - "defaultValue": { - "enabled": true, - "name": "[format('id-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]" - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Managed Identity resource." - } - }, - "networkSecurityGroupBackendConfiguration": { - "$ref": "#/definitions/networkSecurityGroupConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('nsg-backend-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "securityRules": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the backend subnet." - } - }, - "networkSecurityGroupContainersConfiguration": { - "$ref": "#/definitions/networkSecurityGroupConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('nsg-containers-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "securityRules": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the containers subnet." - } - }, - "networkSecurityGroupBastionConfiguration": { - "$ref": "#/definitions/networkSecurityGroupConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('nsg-bastion-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "securityRules": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the Bastion subnet." - } - }, - "networkSecurityGroupAdministrationConfiguration": { - "$ref": "#/definitions/networkSecurityGroupConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('nsg-administration-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "securityRules": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the administration subnet." - } - }, - "virtualNetworkConfiguration": { - "$ref": "#/definitions/virtualNetworkConfigurationType", - "defaultValue": { - "enabled": "[if(parameters('useWafAlignedArchitecture'), true(), false())]", - "name": "[format('vnet-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "addressPrefixes": null, - "subnets": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine virtual network resource." - } - }, - "bastionConfiguration": { - "$ref": "#/definitions/bastionConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('bas-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "sku": "Standard", - "virtualNetworkResourceId": null, - "publicIpResourceName": "[format('pip-bas{0}', parameters('solutionPrefix'))]" - }, - "metadata": { - "description": "Optional. The configuration to apply for the Multi-Agent Custom Automation Engine bastion resource." - } - }, - "virtualMachineConfiguration": { - "$ref": "#/definitions/virtualMachineConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('vm{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "adminUsername": "adminuser", - "adminPassword": "[if(parameters('useWafAlignedArchitecture'), 'P@ssw0rd1234', guid(parameters('solutionPrefix'), subscription().subscriptionId))]", - "vmSize": "Standard_D2s_v3", - "subnetResourceId": null - }, - "metadata": { - "description": "Optional. Configuration for the Windows virtual machine." - } - }, - "aiFoundryAiServicesConfiguration": { - "$ref": "#/definitions/aiServicesConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('aisa-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('aiDeploymentsLocation')]", - "sku": "S0", - "deployments": null, - "subnetResourceId": null, - "modelCapacity": "[parameters('gptModelCapacity')]" - }, - "metadata": { - "description": "Optional. The configuration to apply for the AI Foundry AI Services resource." - } - }, - "aiFoundryAiProjectConfiguration": { - "$ref": "#/definitions/aiProjectConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('aifp-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('aiDeploymentsLocation')]", - "sku": "Basic", - "tags": "[parameters('tags')]" - }, - "metadata": { - "description": "Optional. The configuration to apply for the AI Foundry AI Project resource." - } - }, - "cosmosDbAccountConfiguration": { - "$ref": "#/definitions/cosmosDbAccountConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('cosmos-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "subnetResourceId": null, - "sqlDatabases": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Cosmos DB Account resource." - } - }, - "containerAppEnvironmentConfiguration": { - "$ref": "#/definitions/containerAppEnvironmentConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('cae-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "subnetResourceId": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Container App Environment resource." - } - }, - "containerAppConfiguration": { - "$ref": "#/definitions/containerAppConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('ca-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "tags": "[parameters('tags')]", - "environmentResourceId": null, - "concurrentRequests": "100", - "containerCpu": "2.0", - "containerMemory": "4.0Gi", - "containerImageRegistryDomain": "biabcontainerreg.azurecr.io", - "containerImageName": "macaebackend", - "containerImageTag": "[parameters('imageTag')]", - "containerName": "backend", - "ingressTargetPort": 8000, - "maxReplicas": 1, - "minReplicas": 1 - }, - "metadata": { - "description": "Optional. The configuration to apply for the Container App resource." - } - }, - "webServerFarmConfiguration": { - "$ref": "#/definitions/webServerFarmConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('asp-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "skuName": "[if(parameters('useWafAlignedArchitecture'), 'P1v3', 'B2')]", - "skuCapacity": "[if(parameters('useWafAlignedArchitecture'), 3, 1)]", - "tags": "[parameters('tags')]" - }, - "metadata": { - "description": "Optional. The configuration to apply for the Web Server Farm resource." - } - }, - "webSiteConfiguration": { - "$ref": "#/definitions/webSiteConfigurationType", - "defaultValue": { - "enabled": true, - "name": "[format('app-{0}', parameters('solutionPrefix'))]", - "location": "[parameters('solutionLocation')]", - "containerImageRegistryDomain": "biabcontainerreg.azurecr.io", - "containerImageName": "macaefrontend", - "containerImageTag": "[parameters('imageTag')]", - "containerName": "backend", - "tags": "[parameters('tags')]", - "environmentResourceId": null - }, - "metadata": { - "description": "Optional. The configuration to apply for the Web Server Farm resource." - } - } - }, - "variables": { - "deployerInfo": "[deployer()]", - "deployingUserPrincipalId": "[variables('deployerInfo').objectId]", - "logAnalyticsWorkspaceEnabled": "[coalesce(tryGet(parameters('logAnalyticsWorkspaceConfiguration'), 'enabled'), true())]", - "logAnalyticsWorkspaceResourceName": "[coalesce(tryGet(parameters('logAnalyticsWorkspaceConfiguration'), 'name'), format('log-{0}', parameters('solutionPrefix')))]", - "existingWorkspaceResourceId": "[coalesce(tryGet(parameters('logAnalyticsWorkspaceConfiguration'), 'existingWorkspaceResourceId'), '')]", - "useExistingWorkspace": "[not(equals(variables('existingWorkspaceResourceId'), ''))]", - "applicationInsightsEnabled": "[coalesce(tryGet(parameters('applicationInsightsConfiguration'), 'enabled'), true())]", - "applicationInsightsResourceName": "[coalesce(tryGet(parameters('applicationInsightsConfiguration'), 'name'), format('appi-{0}', parameters('solutionPrefix')))]", - "userAssignedManagedIdentityEnabled": "[coalesce(tryGet(parameters('userAssignedManagedIdentityConfiguration'), 'enabled'), true())]", - "userAssignedManagedIdentityResourceName": "[coalesce(tryGet(parameters('userAssignedManagedIdentityConfiguration'), 'name'), format('id-{0}', parameters('solutionPrefix')))]", - "networkSecurityGroupBackendEnabled": "[coalesce(tryGet(parameters('networkSecurityGroupBackendConfiguration'), 'enabled'), true())]", - "networkSecurityGroupBackendResourceName": "[coalesce(tryGet(parameters('networkSecurityGroupBackendConfiguration'), 'name'), format('nsg-backend-{0}', parameters('solutionPrefix')))]", - "networkSecurityGroupContainersEnabled": "[coalesce(tryGet(parameters('networkSecurityGroupContainersConfiguration'), 'enabled'), true())]", - "networkSecurityGroupContainersResourceName": "[coalesce(tryGet(parameters('networkSecurityGroupContainersConfiguration'), 'name'), format('nsg-containers-{0}', parameters('solutionPrefix')))]", - "networkSecurityGroupBastionEnabled": "[coalesce(tryGet(parameters('networkSecurityGroupBastionConfiguration'), 'enabled'), true())]", - "networkSecurityGroupBastionResourceName": "[coalesce(tryGet(parameters('networkSecurityGroupBastionConfiguration'), 'name'), format('nsg-bastion-{0}', parameters('solutionPrefix')))]", - "networkSecurityGroupAdministrationEnabled": "[coalesce(tryGet(parameters('networkSecurityGroupAdministrationConfiguration'), 'enabled'), true())]", - "networkSecurityGroupAdministrationResourceName": "[coalesce(tryGet(parameters('networkSecurityGroupAdministrationConfiguration'), 'name'), format('nsg-administration-{0}', parameters('solutionPrefix')))]", - "virtualNetworkEnabled": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'enabled'), true())]", - "virtualNetworkResourceName": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'name'), format('vnet-{0}', parameters('solutionPrefix')))]", - "bastionEnabled": "[coalesce(tryGet(parameters('bastionConfiguration'), 'enabled'), true())]", - "bastionResourceName": "[coalesce(tryGet(parameters('bastionConfiguration'), 'name'), format('bas-{0}', parameters('solutionPrefix')))]", - "virtualMachineEnabled": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'enabled'), true())]", - "virtualMachineResourceName": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'name'), format('vm{0}', parameters('solutionPrefix')))]", - "openAiSubResource": "account", - "openAiPrivateDnsZones": { - "privatelink.cognitiveservices.azure.com": "[variables('openAiSubResource')]", - "privatelink.openai.azure.com": "[variables('openAiSubResource')]", - "privatelink.services.ai.azure.com": "[variables('openAiSubResource')]" - }, - "useExistingFoundryProject": "[not(empty(parameters('existingFoundryProjectResourceId')))]", - "existingAiFoundryName": "[if(variables('useExistingFoundryProject'), split(parameters('existingFoundryProjectResourceId'), '/')[8], '')]", - "aiFoundryAiServicesResourceName": "[if(variables('useExistingFoundryProject'), variables('existingAiFoundryName'), coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'name'), format('aisa-{0}', parameters('solutionPrefix'))))]", - "aiFoundryAIservicesEnabled": "[coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'enabled'), true())]", - "aiFoundryAiServicesModelDeployment": { - "format": "OpenAI", - "name": "[parameters('gptModelName')]", - "version": "[parameters('gptModelVersion')]", - "sku": { - "name": "[parameters('modelDeploymentType')]", - "capacity": "[coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'modelCapacity'), parameters('gptModelCapacity'))]" - }, - "raiPolicyName": "Microsoft.Default" - }, - "existingAiFounryProjectName": "[if(variables('useExistingFoundryProject'), last(split(parameters('existingFoundryProjectResourceId'), '/')), '')]", - "aiFoundryAiProjectName": "[if(variables('useExistingFoundryProject'), variables('existingAiFounryProjectName'), coalesce(tryGet(parameters('aiFoundryAiProjectConfiguration'), 'name'), format('aifp-{0}', parameters('solutionPrefix'))))]", - "useExistingResourceId": "[not(empty(parameters('existingFoundryProjectResourceId')))]", - "cosmosDbAccountEnabled": "[coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'enabled'), true())]", - "cosmosDbResourceName": "[coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'name'), format('cosmos-{0}', parameters('solutionPrefix')))]", - "cosmosDbDatabaseName": "macae", - "cosmosDbDatabaseMemoryContainerName": "memory", - "containerAppEnvironmentEnabled": "[coalesce(tryGet(parameters('containerAppEnvironmentConfiguration'), 'enabled'), true())]", - "containerAppEnvironmentResourceName": "[coalesce(tryGet(parameters('containerAppEnvironmentConfiguration'), 'name'), format('cae-{0}', parameters('solutionPrefix')))]", - "containerAppEnabled": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'enabled'), true())]", - "containerAppResourceName": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'name'), format('ca-{0}', parameters('solutionPrefix')))]", - "containerAppMcpResourceName": "[format('ca-mcp-{0}', parameters('solutionPrefix'))]", - "webServerFarmEnabled": "[coalesce(tryGet(parameters('webServerFarmConfiguration'), 'enabled'), true())]", - "webServerFarmResourceName": "[coalesce(tryGet(parameters('webServerFarmConfiguration'), 'name'), format('asp-{0}', parameters('solutionPrefix')))]", - "webSiteEnabled": "[coalesce(tryGet(parameters('webSiteConfiguration'), 'enabled'), true())]", - "webSiteName": "[format('app-{0}', parameters('solutionPrefix'))]" - }, - "resources": { - "resourceGroupTags": { - "type": "Microsoft.Resources/tags", - "apiVersion": "2021-04-01", - "name": "default", - "properties": { - "tags": "[shallowMerge(createArray(parameters('tags'), createObject('TemplateName', 'Macae')))]" - } - }, - "logAnalyticsWorkspace": { - "condition": "[and(variables('logAnalyticsWorkspaceEnabled'), not(variables('useExistingWorkspace')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('logAnalyticsWorkspaceResourceName')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('logAnalyticsWorkspaceConfiguration'), 'tags'), parameters('tags'))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('logAnalyticsWorkspaceConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "skuName": { - "value": "[coalesce(tryGet(parameters('logAnalyticsWorkspaceConfiguration'), 'sku'), 'PerGB2018')]" - }, - "dataRetention": { - "value": "[coalesce(tryGet(parameters('logAnalyticsWorkspaceConfiguration'), 'dataRetentionInDays'), 365)]" - }, - "diagnosticSettings": { - "value": [ - { - "useThisWorkspace": true - } - ] - } - }, - "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.35.1.17967", - "templateHash": "10549387460031423688" - }, - "name": "Log Analytics Workspaces", - "description": "This module deploys a Log Analytics Workspace." - }, - "definitions": { - "diagnosticSettingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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." - } - }, - "useThisWorkspace": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." - } - }, - "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." - } - } - } - }, - "gallerySolutionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the gallery solutions to be created in the log analytics workspace." - } - }, - "storageInsightsConfigType": { - "type": "object", - "properties": { - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the storage account to be linked." - } - }, - "containers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of tables to be read by the workspace." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the storage insights configuration." - } - }, - "linkedServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the linked service." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require read access." - } - }, - "writeAccessResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace. This should be used for linking resources which require write access." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked service." - } - }, - "linkedStorageAccountType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the link." - } - }, - "storageAccountIds": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the linked storage account." - } - }, - "savedSearchType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "etag": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. The category of the saved search. This helps the user to find a saved search faster." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "functionAlias": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The function alias if query serves as a function." - } - }, - "functionParameters": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: 'param-name1:type1 = default_value1, param-name2:type2 = default_value2'. For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. The query expression for the saved search." - } - }, - "tags": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The tags attached to the saved search." - } - }, - "version": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The version number of the query language. The current version is 2 and is the default." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the saved search." - } - }, - "dataExportType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data export." - } - }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, - "metadata": { - "description": "Optional. The destination of the data export." - } - }, - "enable": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable or disable the data export." - } - }, - "tableNames": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of table names to export." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the data export." - } - }, - "dataSourceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "metadata": { - "description": "Required. The kind of data source." - } - }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the resource that will be linked to the workspace." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the event log to configure when kind is WindowsEvent." - } - }, - "eventTypes": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "intervalSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." - } - }, - "syslogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." - } - }, - "syslogSeverities": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to configure in the resource." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the data source." - } - }, - "tableType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "plan": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The plan for the table." - } - }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, - "metadata": { - "description": "Optional. The restored logs for the table." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. The schema for the table." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, - "metadata": { - "description": "Optional. The search results for the table." - } - }, - "retentionInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The retention in days for the table." - } - }, - "totalRetentionInDays": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The total retention in days for the table." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The role assignments for the table." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Properties of the custom table." - } - }, - "workspaceFeaturesType": { - "type": "object", - "properties": { - "disableLocalAuth": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Disable Non-EntraID based Auth. Default is true." - } - }, - "enableDataExport": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag that indicate if data should be exported." - } - }, - "enableLogAccessUsingOnlyResourcePermissions": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable log access using only resource permissions. Default is false." - } - }, - "immediatePurgeDataOn30Days": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Flag that describes if we want to remove the data after 30 days." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Features of the workspace." - } - }, - "_1.columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], - "metadata": { - "description": "Required. The column type." - } - }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], - "nullable": true, - "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Column display name." - } - } - }, - "metadata": { - "description": "The parameters of the table column.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "destinationType": { - "type": "object", - "properties": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The destination resource ID." - } - }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination metadata." - } - } - }, - "metadata": { - "description": "The data export destination properties.", - "__bicep_imported_from!": { - "sourceTemplate": "data-export/main.bicep" - } - } - }, - "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." - } - } - }, - "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.2.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - }, - "restoredLogsType": { - "type": "object", - "properties": { - "sourceTable": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table to restore data from." - } - }, - "startRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." - } - }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the restore operation that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "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.2.1" - } - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "description": "The table schema.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "description": "The parameters of the search job that initiated the table.", - "__bicep_imported_from!": { - "sourceTemplate": "table/main.bicep" - } - } - }, - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/res/operations-management/solution:0.3.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Log Analytics workspace." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "skuName": { - "type": "string", - "defaultValue": "PerGB2018", - "allowedValues": [ - "CapacityReservation", - "Free", - "LACluster", - "PerGB2018", - "PerNode", - "Premium", - "Standalone", - "Standard" - ], - "metadata": { - "description": "Optional. The name of the SKU." - } - }, - "skuCapacityReservationLevel": { - "type": "int", - "defaultValue": 100, - "minValue": 100, - "maxValue": 5000, - "metadata": { - "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." - } - }, - "storageInsightsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/storageInsightsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of storage accounts to be read by the workspace." - } - }, - "linkedServices": { - "type": "array", - "items": { - "$ref": "#/definitions/linkedServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of services to be linked." - } - }, - "linkedStorageAccounts": { - "type": "array", - "items": { - "$ref": "#/definitions/linkedStorageAccountType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." - } - }, - "savedSearches": { - "type": "array", - "items": { - "$ref": "#/definitions/savedSearchType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Kusto Query Language searches to save." - } - }, - "dataExports": { - "type": "array", - "items": { - "$ref": "#/definitions/dataExportType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW data export instances to be deployed." - } - }, - "dataSources": { - "type": "array", - "items": { - "$ref": "#/definitions/dataSourceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW data sources to configure." - } - }, - "tables": { - "type": "array", - "items": { - "$ref": "#/definitions/tableType" - }, - "nullable": true, - "metadata": { - "description": "Optional. LAW custom tables to be deployed." - } - }, - "gallerySolutions": { - "type": "array", - "items": { - "$ref": "#/definitions/gallerySolutionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." - } - }, - "onboardWorkspaceToSentinel": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Onboard the Log Analytics Workspace to Sentinel. Requires 'SecurityInsights' solution to be in gallerySolutions." - } - }, - "dataRetention": { - "type": "int", - "defaultValue": 365, - "minValue": 0, - "maxValue": 730, - "metadata": { - "description": "Optional. Number of days data will be retained for." - } - }, - "dailyQuotaGb": { - "type": "int", - "defaultValue": -1, - "minValue": -1, - "metadata": { - "description": "Optional. The workspace daily quota for ingestion." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics ingestion." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Log Analytics query." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." - } - }, - "features": { - "$ref": "#/definitions/workspaceFeaturesType", - "nullable": true, - "metadata": { - "description": "Optional. The workspace features." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "forceCmkForQuery": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether customer managed storage is mandatory for query management." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "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)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", - "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.11.2', '.', '-'), 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" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "features": { - "searchVersion": 1, - "enableLogAccessUsingOnlyResourcePermissions": "[coalesce(tryGet(parameters('features'), 'enableLogAccessUsingOnlyResourcePermissions'), false())]", - "disableLocalAuth": "[coalesce(tryGet(parameters('features'), 'disableLocalAuth'), true())]", - "enableDataExport": "[tryGet(parameters('features'), 'enableDataExport')]", - "immediatePurgeDataOn30Days": "[tryGet(parameters('features'), 'immediatePurgeDataOn30Days')]" - }, - "sku": { - "name": "[parameters('skuName')]", - "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" - }, - "retentionInDays": "[parameters('dataRetention')]", - "workspaceCapping": { - "dailyQuotaGb": "[parameters('dailyQuotaGb')]" - }, - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "forceCmkForQuery": "[parameters('forceCmkForQuery')]" - }, - "identity": "[variables('identity')]" - }, - "logAnalyticsWorkspace_diagnosticSettings": { - "copy": { - "name": "logAnalyticsWorkspace_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_sentinelOnboarding": { - "condition": "[and(not(empty(filter(coalesce(parameters('gallerySolutions'), createArray()), lambda('item', startsWith(lambdaVariables('item').name, 'SecurityInsights'))))), parameters('onboardWorkspaceToSentinel'))]", - "type": "Microsoft.SecurityInsights/onboardingStates", - "apiVersion": "2024-03-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "default", - "properties": {}, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_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.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_roleAssignments": { - "copy": { - "name": "logAnalyticsWorkspace_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', 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": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_storageInsightConfigs": { - "copy": { - "name": "logAnalyticsWorkspace_storageInsightConfigs", - "count": "[length(coalesce(parameters('storageInsightsConfigs'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "containers": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'containers')]" - }, - "tables": { - "value": "[tryGet(coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()], 'tables')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('storageInsightsConfigs'), createArray())[copyIndex()].storageAccountResourceId]" - } - }, - "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.35.1.17967", - "templateHash": "2043978404537017691" - }, - "name": "Log Analytics Workspace Storage Insight Configs", - "description": "This module deploys a Log Analytics Workspace Storage Insight Config." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the storage insights config." - } - }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Azure Resource Manager ID of the storage account resource." - } - }, - "containers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The names of the blob containers that the workspace should read." - } - }, - "tables": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The names of the Azure tables that the workspace should read." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to configure in the resource." - } - } - }, - "resources": { - "storageAccount": { - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" - }, - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "storageinsightconfig": { - "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "containers": "[parameters('containers')]", - "tables": "[parameters('tables')]", - "storageAccount": { - "id": "[parameters('storageAccountResourceId')]", - "key": "[listKeys('storageAccount', '2022-09-01').keys[0].value]" - } - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed storage insights configuration." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the storage insight configuration is deployed." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the storage insights configuration." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_linkedServices": { - "copy": { - "name": "logAnalyticsWorkspace_linkedServices", - "count": "[length(coalesce(parameters('linkedServices'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedServices'), createArray())[copyIndex()].name]" - }, - "resourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'resourceId')]" - }, - "writeAccessResourceId": { - "value": "[tryGet(coalesce(parameters('linkedServices'), createArray())[copyIndex()], 'writeAccessResourceId')]" - } - }, - "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.35.1.17967", - "templateHash": "15624488954958814427" - }, - "name": "Log Analytics Workspace Linked Services", - "description": "This module deploys a Log Analytics Workspace Linked Service." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the link." - } - }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." - } - }, - "writeAccessResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to configure in the resource." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "linkedService": { - "type": "Microsoft.OperationalInsights/workspaces/linkedServices", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resourceId": "[parameters('resourceId')]", - "writeAccessResourceId": "[parameters('writeAccessResourceId')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed linked service." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed linked service." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the linked service is deployed." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_linkedStorageAccounts": { - "copy": { - "name": "logAnalyticsWorkspace_linkedStorageAccounts", - "count": "[length(coalesce(parameters('linkedStorageAccounts'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].name]" - }, - "storageAccountIds": { - "value": "[coalesce(parameters('linkedStorageAccounts'), createArray())[copyIndex()].storageAccountIds]" - } - }, - "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.35.1.17967", - "templateHash": "8250559094478594611" - }, - "name": "Log Analytics Workspace Linked Storage Accounts", - "description": "This module deploys a Log Analytics Workspace Linked Storage Account." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "allowedValues": [ - "Query", - "Alerts", - "CustomLogs", - "AzureWatson" - ], - "metadata": { - "description": "Required. Name of the link." - } - }, - "storageAccountIds": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. Linked storage accounts resources Ids." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "linkedStorageAccount": { - "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "properties": { - "storageAccountIds": "[parameters('storageAccountIds')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed linked storage account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed linked storage account." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the linked storage account is deployed." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_savedSearches": { - "copy": { - "name": "logAnalyticsWorkspace_savedSearches", - "count": "[length(coalesce(parameters('savedSearches'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[format('{0}{1}', coalesce(parameters('savedSearches'), createArray())[copyIndex()].name, uniqueString(deployment().name))]" - }, - "etag": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'etag')]" - }, - "displayName": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].displayName]" - }, - "category": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].category]" - }, - "query": { - "value": "[coalesce(parameters('savedSearches'), createArray())[copyIndex()].query]" - }, - "functionAlias": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionAlias')]" - }, - "functionParameters": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'functionParameters')]" - }, - "tags": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'tags')]" - }, - "version": { - "value": "[tryGet(coalesce(parameters('savedSearches'), createArray())[copyIndex()], 'version')]" - } - }, - "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.35.1.17967", - "templateHash": "5149844663841891327" - }, - "name": "Log Analytics Workspace Saved Searches", - "description": "This module deploys a Log Analytics Workspace Saved Search." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the saved search." - } - }, - "displayName": { - "type": "string", - "metadata": { - "description": "Required. Display name for the search." - } - }, - "category": { - "type": "string", - "metadata": { - "description": "Required. Query category." - } - }, - "query": { - "type": "string", - "metadata": { - "description": "Required. Kusto Query to be stored." - } - }, - "tags": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Tags to configure in the resource." - } - }, - "functionAlias": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The function alias if query serves as a function." - } - }, - "functionParameters": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." - } - }, - "version": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The version number of the query language." - } - }, - "etag": { - "type": "string", - "defaultValue": "*", - "metadata": { - "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "savedSearch": { - "type": "Microsoft.OperationalInsights/workspaces/savedSearches", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "properties": { - "etag": "[parameters('etag')]", - "tags": "[coalesce(parameters('tags'), createArray())]", - "displayName": "[parameters('displayName')]", - "category": "[parameters('category')]", - "query": "[parameters('query')]", - "functionAlias": "[parameters('functionAlias')]", - "functionParameters": "[parameters('functionParameters')]", - "version": "[parameters('version')]" - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed saved search." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the saved search is deployed." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed saved search." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "logAnalyticsWorkspace_linkedStorageAccounts" - ] - }, - "logAnalyticsWorkspace_dataExports": { - "copy": { - "name": "logAnalyticsWorkspace_dataExports", - "count": "[length(coalesce(parameters('dataExports'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "workspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('dataExports'), createArray())[copyIndex()].name]" - }, - "destination": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'destination')]" - }, - "enable": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'enable')]" - }, - "tableNames": { - "value": "[tryGet(coalesce(parameters('dataExports'), createArray())[copyIndex()], 'tableNames')]" - } - }, - "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.35.1.17967", - "templateHash": "1695158270142527557" - }, - "name": "Log Analytics Workspace Data Exports", - "description": "This module deploys a Log Analytics Workspace Data Export." - }, - "definitions": { - "destinationType": { - "type": "object", - "properties": { - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. The destination resource ID." - } - }, - "metaData": { - "type": "object", - "properties": { - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Allows to define an Event Hub name. Not applicable when destination is Storage Account." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination metadata." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The data export destination properties." - } - } - }, - "parameters": { - "name": { - "type": "string", - "minLength": 4, - "maxLength": 63, - "metadata": { - "description": "Required. The data export rule name." - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." - } - }, - "destination": { - "$ref": "#/definitions/destinationType", - "nullable": true, - "metadata": { - "description": "Optional. Destination properties." - } - }, - "enable": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Active when enabled." - } - }, - "tableNames": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "metadata": { - "description": "Required. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('workspaceName')]" - }, - "dataExport": { - "type": "Microsoft.OperationalInsights/workspaces/dataExports", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", - "properties": { - "destination": "[parameters('destination')]", - "enable": "[parameters('enable')]", - "tableNames": "[parameters('tableNames')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the data export." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the data export." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the data export was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_dataSources": { - "copy": { - "name": "logAnalyticsWorkspace_dataSources", - "count": "[length(coalesce(parameters('dataSources'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].name]" - }, - "kind": { - "value": "[coalesce(parameters('dataSources'), createArray())[copyIndex()].kind]" - }, - "linkedResourceId": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'linkedResourceId')]" - }, - "eventLogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventLogName')]" - }, - "eventTypes": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'eventTypes')]" - }, - "objectName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'objectName')]" - }, - "instanceName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'instanceName')]" - }, - "intervalSeconds": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'intervalSeconds')]" - }, - "counterName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'counterName')]" - }, - "state": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'state')]" - }, - "syslogName": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogName')]" - }, - "syslogSeverities": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'syslogSeverities')]" - }, - "performanceCounters": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'performanceCounters')]" - }, - "tags": { - "value": "[tryGet(coalesce(parameters('dataSources'), createArray())[copyIndex()], 'tags')]" - } - }, - "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.35.1.17967", - "templateHash": "3062149733782372246" - }, - "name": "Log Analytics Workspace Datasources", - "description": "This module deploys a Log Analytics Workspace Data Source." - }, - "parameters": { - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the data source." - } - }, - "kind": { - "type": "string", - "defaultValue": "AzureActivityLog", - "allowedValues": [ - "AzureActivityLog", - "WindowsEvent", - "WindowsPerformanceCounter", - "IISLogs", - "LinuxSyslog", - "LinuxSyslogCollection", - "LinuxPerformanceObject", - "LinuxPerformanceCollection" - ], - "metadata": { - "description": "Optional. The kind of the data source." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to configure in the resource." - } - }, - "linkedResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the resource to be linked." - } - }, - "eventLogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Windows event log name to configure when kind is WindowsEvent." - } - }, - "eventTypes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Windows event types to configure when kind is WindowsEvent." - } - }, - "objectName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "instanceName": { - "type": "string", - "defaultValue": "*", - "metadata": { - "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "intervalSeconds": { - "type": "int", - "defaultValue": 60, - "metadata": { - "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." - } - }, - "performanceCounters": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." - } - }, - "counterName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." - } - }, - "state": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." - } - }, - "syslogName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. System log to configure when kind is LinuxSyslog." - } - }, - "syslogSeverities": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Severities to configure when kind is LinuxSyslog." - } - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "dataSource": { - "type": "Microsoft.OperationalInsights/workspaces/dataSources", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", - "kind": "[parameters('kind')]", - "tags": "[parameters('tags')]", - "properties": { - "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", - "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", - "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", - "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", - "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", - "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", - "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", - "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", - "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", - "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", - "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" - } - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed data source." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the data source is deployed." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed data source." - }, - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_tables": { - "copy": { - "name": "logAnalyticsWorkspace_tables", - "count": "[length(coalesce(parameters('tables'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-Table-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "workspaceName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('tables'), createArray())[copyIndex()].name]" - }, - "plan": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'plan')]" - }, - "schema": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'schema')]" - }, - "retentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'retentionInDays')]" - }, - "totalRetentionInDays": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'totalRetentionInDays')]" - }, - "restoredLogs": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'restoredLogs')]" - }, - "searchResults": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'searchResults')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('tables'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.35.1.17967", - "templateHash": "5855172714151847939" - }, - "name": "Log Analytics Workspace Tables", - "description": "This module deploys a Log Analytics Workspace Table." - }, - "definitions": { - "restoredLogsType": { - "type": "object", - "properties": { - "sourceTable": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table to restore data from." - } - }, - "startRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the restore from (UTC)." - } - }, - "endRestoreTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the restore by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the restore operation that initiated the table." - } - }, - "schemaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The table name." - } - }, - "columns": { - "type": "array", - "items": { - "$ref": "#/definitions/columnType" - }, - "metadata": { - "description": "Required. A list of table custom columns." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The table display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The table schema." - } - }, - "columnType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The column name." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "boolean", - "dateTime", - "dynamic", - "guid", - "int", - "long", - "real", - "string" - ], - "metadata": { - "description": "Required. The column type." - } - }, - "dataTypeHint": { - "type": "string", - "allowedValues": [ - "armPath", - "guid", - "ip", - "uri" - ], - "nullable": true, - "metadata": { - "description": "Optional. The column data type logical hint." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The column description." - } - }, - "displayName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Column display name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the table column." - } - }, - "searchResultsType": { - "type": "object", - "properties": { - "query": { - "type": "string", - "metadata": { - "description": "Required. The search job query." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The search description." - } - }, - "limit": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Limit the search job to return up to specified number of rows." - } - }, - "startSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to start the search from (UTC)." - } - }, - "endSearchTime": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The timestamp to end the search by (UTC)." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The parameters of the search job that initiated the table." - } - }, - "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.2.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the table." - } - }, - "workspaceName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." - } - }, - "plan": { - "type": "string", - "defaultValue": "Analytics", - "allowedValues": [ - "Basic", - "Analytics" - ], - "metadata": { - "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." - } - }, - "restoredLogs": { - "$ref": "#/definitions/restoredLogsType", - "nullable": true, - "metadata": { - "description": "Optional. Restore parameters." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": -1, - "minValue": -1, - "maxValue": 730, - "metadata": { - "description": "Optional. The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention." - } - }, - "schema": { - "$ref": "#/definitions/schemaType", - "nullable": true, - "metadata": { - "description": "Optional. Table's schema." - } - }, - "searchResults": { - "$ref": "#/definitions/searchResultsType", - "nullable": true, - "metadata": { - "description": "Optional. Parameters of the search job that initiated this table." - } - }, - "totalRetentionInDays": { - "type": "int", - "defaultValue": -1, - "minValue": -1, - "maxValue": 2555, - "metadata": { - "description": "Optional. The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", - "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", - "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "workspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2023-09-01", - "name": "[parameters('workspaceName')]" - }, - "table": { - "type": "Microsoft.OperationalInsights/workspaces/tables", - "apiVersion": "2023-09-01", - "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", - "properties": { - "plan": "[parameters('plan')]", - "restoredLogs": "[parameters('restoredLogs')]", - "retentionInDays": "[parameters('retentionInDays')]", - "schema": "[parameters('schema')]", - "searchResults": "[parameters('searchResults')]", - "totalRetentionInDays": "[parameters('totalRetentionInDays')]" - } - }, - "table_roleAssignments": { - "copy": { - "name": "table_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), 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": [ - "table" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "logAnalyticsWorkspace_solutions": { - "copy": { - "name": "logAnalyticsWorkspace_solutions", - "count": "[length(coalesce(parameters('gallerySolutions'), createArray()))]" - }, - "condition": "[not(empty(parameters('gallerySolutions')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-LAW-Solution-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].name]" - }, - "location": { - "value": "[parameters('location')]" - }, - "logAnalyticsWorkspaceName": { - "value": "[parameters('name')]" - }, - "plan": { - "value": "[coalesce(parameters('gallerySolutions'), createArray())[copyIndex()].plan]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "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.30.23.60470", - "templateHash": "1867653058254938383" - }, - "name": "Operations Management Solutions", - "description": "This module deploys an Operations Management Solution.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "solutionPlanType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the solution to be created.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, it can be anything.\nThe solution type is case-sensitive.\nIf not provided, the value of the `name` parameter will be used." - } - }, - "product": { - "type": "string", - "metadata": { - "description": "Required. The product name of the deployed solution.\nFor Microsoft published gallery solution it should be `OMSGallery/{solutionType}`, for example `OMSGallery/AntiMalware`.\nFor a third party solution, it can be anything.\nThis is case sensitive." - } - }, - "publisher": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`, which is the default value." - } - } - }, - "metadata": { - "__bicep_export!": true - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the solution.\nFor solutions authored by Microsoft, the name must be in the pattern: `SolutionType(WorkspaceName)`, for example: `AntiMalware(contoso-Logs)`.\nFor solutions authored by third parties, the name should be in the pattern: `SolutionType[WorkspaceName]`, for example `MySolution[contoso-Logs]`.\nThe solution type is case-sensitive." - } - }, - "plan": { - "$ref": "#/definitions/solutionPlanType", - "metadata": { - "description": "Required. Plan for solution object supported by the OperationsManagement resource provider." - } - }, - "logAnalyticsWorkspaceName": { - "type": "string", - "metadata": { - "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.3.0', '.', '-'), 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" - } - } - } - } - }, - "logAnalyticsWorkspace": { - "existing": true, - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2021-06-01", - "name": "[parameters('logAnalyticsWorkspaceName')]" - }, - "solution": { - "type": "Microsoft.OperationsManagement/solutions", - "apiVersion": "2015-11-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "properties": { - "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" - }, - "plan": { - "name": "[coalesce(tryGet(parameters('plan'), 'name'), parameters('name'))]", - "promotionCode": "", - "product": "[parameters('plan').product]", - "publisher": "[coalesce(tryGet(parameters('plan'), 'publisher'), 'Microsoft')]" - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed solution." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed solution." - }, - "value": "[resourceId('Microsoft.OperationsManagement/solutions', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group where the solution is deployed." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('solution', '2015-11-01-preview', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed log analytics workspace." - }, - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed log analytics workspace." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed log analytics workspace." - }, - "value": "[parameters('name')]" - }, - "logAnalyticsWorkspaceId": { - "type": "string", - "metadata": { - "description": "The ID associated with the workspace." - }, - "value": "[reference('logAnalyticsWorkspace').customerId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('logAnalyticsWorkspace', '2023-09-01', 'full').location]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('logAnalyticsWorkspace', '2023-09-01', 'full'), 'identity'), 'principalId')]" - }, - "primarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The primary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2023-09-01').primarySharedKey]" - }, - "secondarySharedKey": { - "type": "securestring", - "metadata": { - "description": "The secondary shared key of the log analytics workspace." - }, - "value": "[listKeys('logAnalyticsWorkspace', '2023-09-01').secondarySharedKey]" - } - } - } - } - }, - "applicationInsights": { - "condition": "[variables('applicationInsightsEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.insights.component.{0}', variables('applicationInsightsResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('applicationInsightsResourceName')]" - }, - "workspaceResourceId": "[if(variables('useExistingWorkspace'), createObject('value', variables('existingWorkspaceResourceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId))]", - "location": { - "value": "[coalesce(tryGet(parameters('applicationInsightsConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('applicationInsightsConfiguration'), 'tags'), parameters('tags'))]" - }, - "retentionInDays": { - "value": "[coalesce(tryGet(parameters('applicationInsightsConfiguration'), 'retentionInDays'), 365)]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "kind": { - "value": "web" - }, - "disableIpMasking": { - "value": false - }, - "flowType": { - "value": "Bluefield" - } - }, - "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.33.93.31351", - "templateHash": "5735496719243704506" - }, - "name": "Application Insights", - "description": "This component deploys an Application Insights instance." - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.3.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." - } - } - }, - "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.5.1" - } - } - }, - "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.3.0" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Application Insights." - } - }, - "applicationType": { - "type": "string", - "defaultValue": "web", - "allowedValues": [ - "web", - "other" - ], - "metadata": { - "description": "Optional. Application type." - } - }, - "workspaceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." - } - }, - "disableIpMasking": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Disable IP masking. Default value is set to true." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." - } - }, - "forceCustomerStorageForProfiler": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Force users to create their own storage account for profiler and debugger." - } - }, - "linkedStorageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Linked storage account resource ID." - } - }, - "publicNetworkAccessForIngestion": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." - } - }, - "publicNetworkAccessForQuery": { - "type": "string", - "defaultValue": "Enabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." - } - }, - "retentionInDays": { - "type": "int", - "defaultValue": 365, - "allowedValues": [ - 30, - 60, - 90, - 120, - 180, - 270, - 365, - 550, - 730 - ], - "metadata": { - "description": "Optional. Retention period in days." - } - }, - "samplingPercentage": { - "type": "int", - "defaultValue": 100, - "minValue": 0, - "maxValue": 100, - "metadata": { - "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." - } - }, - "flowType": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Used by the Application Insights system to determine what kind of flow this component was created by. This is to be set to 'Bluefield' when creating/updating a component via the REST API." - } - }, - "requestSource": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Describes what tool created this Application Insights component. Customers using this API should set this to the default 'rest'." - } - }, - "kind": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "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')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", - "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", - "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", - "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.6.0', '.', '-'), 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" - } - } - } - } - }, - "appInsights": { - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "Application_Type": "[parameters('applicationType')]", - "DisableIpMasking": "[parameters('disableIpMasking')]", - "DisableLocalAuth": "[parameters('disableLocalAuth')]", - "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", - "WorkspaceResourceId": "[parameters('workspaceResourceId')]", - "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", - "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", - "RetentionInDays": "[parameters('retentionInDays')]", - "SamplingPercentage": "[parameters('samplingPercentage')]", - "Flow_Type": "[parameters('flowType')]", - "Request_Source": "[parameters('requestSource')]" - } - }, - "appInsights_roleAssignments": { - "copy": { - "name": "appInsights_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', 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": [ - "appInsights" - ] - }, - "appInsights_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "appInsights_diagnosticSettings": { - "copy": { - "name": "appInsights_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "appInsights" - ] - }, - "linkedStorageAccount": { - "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appInsightsName": { - "value": "[parameters('name')]" - }, - "storageAccountResourceId": { - "value": "[coalesce(parameters('linkedStorageAccountResourceId'), '')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "10861379689695100897" - }, - "name": "Application Insights Linked Storage Account", - "description": "This component deploys an Application Insights Linked Storage Account." - }, - "parameters": { - "appInsightsName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." - } - }, - "storageAccountResourceId": { - "type": "string", - "metadata": { - "description": "Required. Linked storage account resource ID." - } - } - }, - "resources": [ - { - "type": "microsoft.insights/components/linkedStorageAccounts", - "apiVersion": "2020-03-01-preview", - "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", - "properties": { - "linkedStorageAccount": "[parameters('storageAccountResourceId')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Linked Storage Account." - }, - "value": "ServiceProfiler" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Linked Storage Account." - }, - "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the agent pool was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "appInsights" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the application insights component." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the application insights component." - }, - "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the application insights component was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "applicationId": { - "type": "string", - "metadata": { - "description": "The application ID of the application insights component." - }, - "value": "[reference('appInsights').AppId]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('appInsights', '2020-02-02', 'full').location]" - }, - "instrumentationKey": { - "type": "string", - "metadata": { - "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." - }, - "value": "[reference('appInsights').InstrumentationKey]" - }, - "connectionString": { - "type": "string", - "metadata": { - "description": "Application Insights Connection String." - }, - "value": "[reference('appInsights').ConnectionString]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "userAssignedIdentity": { - "condition": "[variables('userAssignedManagedIdentityEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.managed-identity.user-assigned-identity.{0}', variables('userAssignedManagedIdentityResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('userAssignedManagedIdentityResourceName')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('userAssignedManagedIdentityConfiguration'), 'tags'), parameters('tags'))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('userAssignedManagedIdentityConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - } - }, - "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.34.44.8038", - "templateHash": "16707109626832623586" - }, - "name": "User Assigned Identities", - "description": "This module deploys a User Assigned Identity." - }, - "definitions": { - "federatedIdentityCredentialType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the federated identity credential." - } - }, - "audiences": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external identity." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the federated identity credential." - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the User Assigned Identity." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "federatedIdentityCredentials": { - "type": "array", - "items": { - "$ref": "#/definitions/federatedIdentityCredentialType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "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')]", - "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", - "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.4.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" - } - } - } - } - }, - "userAssignedIdentity": { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2024-11-30", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "userAssignedIdentity_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.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_roleAssignments": { - "copy": { - "name": "userAssignedIdentity_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', 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": [ - "userAssignedIdentity" - ] - }, - "userAssignedIdentity_federatedIdentityCredentials": { - "copy": { - "name": "userAssignedIdentity_federatedIdentityCredentials", - "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-UserMSI-FederatedIdentityCred-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" - }, - "userAssignedIdentityName": { - "value": "[parameters('name')]" - }, - "audiences": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" - }, - "issuer": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" - }, - "subject": { - "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "13656021764446440473" - }, - "name": "User Assigned Identity Federated Identity Credential", - "description": "This module deploys a User Assigned Identity Federated Identity Credential." - }, - "parameters": { - "userAssignedIdentityName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret." - } - }, - "audiences": { - "type": "array", - "metadata": { - "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." - } - }, - "issuer": { - "type": "string", - "metadata": { - "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." - } - }, - "subject": { - "type": "string", - "metadata": { - "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." - } - } - }, - "resources": [ - { - "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", - "apiVersion": "2024-11-30", - "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", - "properties": { - "audiences": "[parameters('audiences')]", - "issuer": "[parameters('issuer')]", - "subject": "[parameters('subject')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the federated identity credential." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the federated identity credential." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the federated identity credential was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "userAssignedIdentity" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the user assigned identity." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the user assigned identity." - }, - "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The principal ID (object ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').principalId]" - }, - "clientId": { - "type": "string", - "metadata": { - "description": "The client ID (application ID) of the user assigned identity." - }, - "value": "[reference('userAssignedIdentity').clientId]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the user assigned identity was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('userAssignedIdentity', '2024-11-30', 'full').location]" - } - } - } - } - }, - "networkSecurityGroupBackend": { - "condition": "[and(variables('virtualNetworkEnabled'), variables('networkSecurityGroupBackendEnabled'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.network-security-group.{0}', variables('networkSecurityGroupBackendResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('networkSecurityGroupBackendResourceName')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupBackendConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupBackendConfiguration'), 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "securityRules": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupBackendConfiguration'), 'securityRules'), createArray())]" - } - }, - "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.33.93.31351", - "templateHash": "2305747478751645177" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." - }, - "definitions": { - "securityRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "metadata": { - "description": "Required. The properties of the security rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a security rule." - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the NSG resource." - } - }, - "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')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.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" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", - "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_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/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', 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": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "networkSecurityGroupContainers": { - "condition": "[and(variables('virtualNetworkEnabled'), variables('networkSecurityGroupContainersEnabled'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.network-security-group.{0}', variables('networkSecurityGroupContainersResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('networkSecurityGroupContainersResourceName')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupContainersConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupContainersConfiguration'), 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "securityRules": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupContainersConfiguration'), 'securityRules'), createArray())]" - } - }, - "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.33.93.31351", - "templateHash": "2305747478751645177" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." - }, - "definitions": { - "securityRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "metadata": { - "description": "Required. The properties of the security rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a security rule." - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the NSG resource." - } - }, - "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')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.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" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", - "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_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/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', 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": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "networkSecurityGroupBastion": { - "condition": "[and(variables('virtualNetworkEnabled'), variables('networkSecurityGroupBastionEnabled'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.network-security-group.{0}', variables('networkSecurityGroupBastionResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('networkSecurityGroupBastionResourceName')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupBastionConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupBastionConfiguration'), 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "securityRules": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupBastionConfiguration'), 'securityRules'), createArray(createObject('name', 'AllowHttpsInBound', 'properties', createObject('protocol', 'Tcp', 'sourcePortRange', '*', 'sourceAddressPrefix', 'Internet', 'destinationPortRange', '443', 'destinationAddressPrefix', '*', 'access', 'Allow', 'priority', 100, 'direction', 'Inbound')), createObject('name', 'AllowGatewayManagerInBound', 'properties', createObject('protocol', 'Tcp', 'sourcePortRange', '*', 'sourceAddressPrefix', 'GatewayManager', 'destinationPortRange', '443', 'destinationAddressPrefix', '*', 'access', 'Allow', 'priority', 110, 'direction', 'Inbound')), createObject('name', 'AllowLoadBalancerInBound', 'properties', createObject('protocol', 'Tcp', 'sourcePortRange', '*', 'sourceAddressPrefix', 'AzureLoadBalancer', 'destinationPortRange', '443', 'destinationAddressPrefix', '*', 'access', 'Allow', 'priority', 120, 'direction', 'Inbound')), createObject('name', 'AllowBastionHostCommunicationInBound', 'properties', createObject('protocol', '*', 'sourcePortRange', '*', 'sourceAddressPrefix', 'VirtualNetwork', 'destinationPortRanges', createArray('8080', '5701'), 'destinationAddressPrefix', 'VirtualNetwork', 'access', 'Allow', 'priority', 130, 'direction', 'Inbound')), createObject('name', 'DenyAllInBound', 'properties', createObject('protocol', '*', 'sourcePortRange', '*', 'sourceAddressPrefix', '*', 'destinationPortRange', '*', 'destinationAddressPrefix', '*', 'access', 'Deny', 'priority', 1000, 'direction', 'Inbound')), createObject('name', 'AllowSshRdpOutBound', 'properties', createObject('protocol', 'Tcp', 'sourcePortRange', '*', 'sourceAddressPrefix', '*', 'destinationPortRanges', createArray('22', '3389'), 'destinationAddressPrefix', 'VirtualNetwork', 'access', 'Allow', 'priority', 100, 'direction', 'Outbound')), createObject('name', 'AllowAzureCloudCommunicationOutBound', 'properties', createObject('protocol', 'Tcp', 'sourcePortRange', '*', 'sourceAddressPrefix', '*', 'destinationPortRange', '443', 'destinationAddressPrefix', 'AzureCloud', 'access', 'Allow', 'priority', 110, 'direction', 'Outbound')), createObject('name', 'AllowBastionHostCommunicationOutBound', 'properties', createObject('protocol', '*', 'sourcePortRange', '*', 'sourceAddressPrefix', 'VirtualNetwork', 'destinationPortRanges', createArray('8080', '5701'), 'destinationAddressPrefix', 'VirtualNetwork', 'access', 'Allow', 'priority', 120, 'direction', 'Outbound')), createObject('name', 'AllowGetSessionInformationOutBound', 'properties', createObject('protocol', '*', 'sourcePortRange', '*', 'sourceAddressPrefix', '*', 'destinationAddressPrefix', 'Internet', 'destinationPortRanges', createArray('80', '443'), 'access', 'Allow', 'priority', 130, 'direction', 'Outbound')), createObject('name', 'DenyAllOutBound', 'properties', createObject('protocol', '*', 'sourcePortRange', '*', 'destinationPortRange', '*', 'sourceAddressPrefix', '*', 'destinationAddressPrefix', '*', 'access', 'Deny', 'priority', 1000, 'direction', 'Outbound'))))]" - } - }, - "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.33.93.31351", - "templateHash": "2305747478751645177" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." - }, - "definitions": { - "securityRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "metadata": { - "description": "Required. The properties of the security rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a security rule." - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the NSG resource." - } - }, - "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')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.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" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", - "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_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/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', 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": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "networkSecurityGroupAdministration": { - "condition": "[and(variables('virtualNetworkEnabled'), variables('networkSecurityGroupAdministrationEnabled'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.network-security-group.{0}', variables('networkSecurityGroupAdministrationResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('networkSecurityGroupAdministrationResourceName')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupAdministrationConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupAdministrationConfiguration'), 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "securityRules": { - "value": "[coalesce(tryGet(parameters('networkSecurityGroupAdministrationConfiguration'), 'securityRules'), createArray())]" - } - }, - "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.33.93.31351", - "templateHash": "2305747478751645177" - }, - "name": "Network Security Groups", - "description": "This module deploys a Network security Group (NSG)." - }, - "definitions": { - "securityRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the security rule." - } - }, - "properties": { - "type": "object", - "properties": { - "access": { - "type": "string", - "allowedValues": [ - "Allow", - "Deny" - ], - "metadata": { - "description": "Required. Whether network traffic is allowed or denied." - } - }, - "description": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The description of the security rule." - } - }, - "destinationAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Optional. The destination address prefix. CIDR or destination IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used." - } - }, - "destinationAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination address prefixes. CIDR or destination IP ranges." - } - }, - "destinationApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as destination." - } - }, - "destinationPortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "destinationPortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The destination port ranges." - } - }, - "direction": { - "type": "string", - "allowedValues": [ - "Inbound", - "Outbound" - ], - "metadata": { - "description": "Required. The direction of the rule. The direction specifies if rule will be evaluated on incoming or outgoing traffic." - } - }, - "priority": { - "type": "int", - "minValue": 100, - "maxValue": 4096, - "metadata": { - "description": "Required. Required. The priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule." - } - }, - "protocol": { - "type": "string", - "allowedValues": [ - "*", - "Ah", - "Esp", - "Icmp", - "Tcp", - "Udp" - ], - "metadata": { - "description": "Required. Network protocol this rule applies to." - } - }, - "sourceAddressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP range. Asterisk \"*\" can also be used to match all source IPs. Default tags such as \"VirtualNetwork\", \"AzureLoadBalancer\" and \"Internet\" can also be used. If this is an ingress rule, specifies where network traffic originates from." - } - }, - "sourceAddressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The CIDR or source IP ranges." - } - }, - "sourceApplicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource IDs of the application security groups specified as source." - } - }, - "sourcePortRange": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The source port or range. Integer or range between 0 and 65535. Asterisk \"*\" can also be used to match all ports." - } - }, - "sourcePortRanges": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The source port ranges." - } - } - }, - "metadata": { - "description": "Required. The properties of the security rule." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of a security rule." - } - }, - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Network Security Group." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "securityRules": { - "type": "array", - "items": { - "$ref": "#/definitions/securityRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of Security Rules to deploy to the Network Security Group. When not provided, an NSG including only the built-in roles will be deployed." - } - }, - "flushConnection": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. When enabled, flows created from Network Security Group connections will be re-evaluated when rules are updates. Initial enablement will trigger re-evaluation. Network Security Group connection flushing is not available in all regions." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the NSG resource." - } - }, - "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')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networksecuritygroup.{0}.{1}', replace('0.5.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" - } - } - } - } - }, - "networkSecurityGroup": { - "type": "Microsoft.Network/networkSecurityGroups", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "securityRules", - "count": "[length(coalesce(parameters('securityRules'), createArray()))]", - "input": { - "name": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].name]", - "properties": { - "access": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.access]", - "description": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'description'), '')]", - "destinationAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefix'), '')]", - "destinationAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationAddressPrefixes'), createArray())]", - "destinationApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationApplicationSecurityGroupResourceIds'), createArray()), lambda('destinationApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('destinationApplicationSecurityGroupResourceId'))))]", - "destinationPortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRange'), '')]", - "destinationPortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'destinationPortRanges'), createArray())]", - "direction": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.direction]", - "priority": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.priority]", - "protocol": "[coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties.protocol]", - "sourceAddressPrefix": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefix'), '')]", - "sourceAddressPrefixes": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceAddressPrefixes'), createArray())]", - "sourceApplicationSecurityGroups": "[map(coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourceApplicationSecurityGroupResourceIds'), createArray()), lambda('sourceApplicationSecurityGroupResourceId', createObject('id', lambdaVariables('sourceApplicationSecurityGroupResourceId'))))]", - "sourcePortRange": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRange'), '')]", - "sourcePortRanges": "[coalesce(tryGet(coalesce(parameters('securityRules'), createArray())[copyIndex('securityRules')].properties, 'sourcePortRanges'), createArray())]" - } - } - } - ], - "flushConnection": "[parameters('flushConnection')]" - } - }, - "networkSecurityGroup_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/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_diagnosticSettings": { - "copy": { - "name": "networkSecurityGroup_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkSecurityGroup" - ] - }, - "networkSecurityGroup_roleAssignments": { - "copy": { - "name": "networkSecurityGroup_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkSecurityGroups', 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": [ - "networkSecurityGroup" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the network security group was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the network security group." - }, - "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the network security group." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkSecurityGroup', '2023-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "virtualNetwork": { - "condition": "[variables('virtualNetworkEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.virtual-network.{0}', variables('virtualNetworkResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('virtualNetworkResourceName')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "addressPrefixes": { - "value": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'addressPrefixes'), createArray('10.0.0.0/8'))]" - }, - "subnets": { - "value": "[coalesce(tryGet(parameters('virtualNetworkConfiguration'), 'subnets'), createArray(createObject('name', 'backend', 'addressPrefix', '10.0.0.0/27', 'networkSecurityGroupResourceId', reference('networkSecurityGroupBackend').outputs.resourceId.value), createObject('name', 'administration', 'addressPrefix', '10.0.0.32/27', 'networkSecurityGroupResourceId', reference('networkSecurityGroupAdministration').outputs.resourceId.value), createObject('name', 'AzureBastionSubnet', 'addressPrefix', '10.0.0.64/26', 'networkSecurityGroupResourceId', reference('networkSecurityGroupBastion').outputs.resourceId.value), createObject('name', 'containers', 'addressPrefix', '10.0.2.0/23', 'delegation', 'Microsoft.App/environments', 'networkSecurityGroupResourceId', reference('networkSecurityGroupContainers').outputs.resourceId.value, 'privateEndpointNetworkPolicies', 'Disabled', 'privateLinkServiceNetworkPolicies', 'Enabled')))]" - } - }, - "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.34.1.11899", - "templateHash": "4090376738500728310" - }, - "name": "Virtual Networks", - "description": "This module deploys a Virtual Network (vNet)." - }, - "definitions": { - "peeringType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be peer-localVnetName-remoteVnetName." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." - } - }, - "useRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - }, - "remotePeeringEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Deploy the outbound and the inbound peering." - } - }, - "remotePeeringName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the VNET Peering resource in the remove Virtual Network. If not provided, default value will be peer-remoteVnetName-localVnetName." - } - }, - "remotePeeringAllowForwardedTraffic": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "remotePeeringAllowGatewayTransit": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "remotePeeringAllowVirtualNetworkAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "remotePeeringDoNotVerifyRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Do not verify the provisioning state of the remote gateway. Default is true." - } - }, - "remotePeeringUseRemoteGateways": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - } - }, - "subnetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. enable or disable apply network policies on private link service in the subnet." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "items": { - "type": "object" - }, - "nullable": true, - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, - "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty." - } - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - }, - "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." - } - } - }, - "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.2.1" - } - } - }, - "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.2.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Virtual Network (vNet)." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "Required. An Array of 1 or more IP Address Prefixes for the Virtual Network." - } - }, - "virtualNetworkBgpCommunity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The BGP community associated with the virtual network." - } - }, - "subnets": { - "type": "array", - "items": { - "$ref": "#/definitions/subnetType" - }, - "nullable": true, - "metadata": { - "description": "Optional. An Array of subnets to deploy to the Virtual Network." - } - }, - "dnsServers": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. DNS Servers associated to the Virtual Network." - } - }, - "ddosProtectionPlanResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the DDoS protection plan to assign the VNET to. If it's left blank, DDoS protection will not be configured. If it's provided, the VNET created by this template will be attached to the referenced DDoS protection plan. The DDoS protection plan can exist in the same or in a different subscription." - } - }, - "peerings": { - "type": "array", - "items": { - "$ref": "#/definitions/peeringType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Virtual Network Peering configurations." - } - }, - "vnetEncryption": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates if encryption is enabled on virtual network and if VM without encryption is allowed in encrypted VNet. Requires the EnableVNetEncryption feature to be registered for the subscription and a supported region to use this property." - } - }, - "vnetEncryptionEnforcement": { - "type": "string", - "defaultValue": "AllowUnencrypted", - "allowedValues": [ - "AllowUnencrypted", - "DropUnencrypted" - ], - "metadata": { - "description": "Optional. If the encrypted VNet allows VM that does not support encryption. Can only be used when vnetEncryption is enabled." - } - }, - "flowTimeoutInMinutes": { - "type": "int", - "defaultValue": 0, - "maxValue": 30, - "metadata": { - "description": "Optional. The flow timeout in minutes for the Virtual Network, which is used to enable connection tracking for intra-VM flows. Possible values are between 4 and 30 minutes. Default value 0 will set the property to null." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableVmProtection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Indicates if VM protection is enabled for all the subnets in the virtual network." - } - } - }, - "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)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetwork.{0}.{1}', replace('0.6.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" - } - } - } - } - }, - "virtualNetwork": { - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "addressSpace": { - "addressPrefixes": "[parameters('addressPrefixes')]" - }, - "bgpCommunities": "[if(not(empty(parameters('virtualNetworkBgpCommunity'))), createObject('virtualNetworkCommunity', parameters('virtualNetworkBgpCommunity')), null())]", - "ddosProtectionPlan": "[if(not(empty(parameters('ddosProtectionPlanResourceId'))), createObject('id', parameters('ddosProtectionPlanResourceId')), null())]", - "dhcpOptions": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', array(parameters('dnsServers'))), null())]", - "enableDdosProtection": "[not(empty(parameters('ddosProtectionPlanResourceId')))]", - "encryption": "[if(equals(parameters('vnetEncryption'), true()), createObject('enabled', parameters('vnetEncryption'), 'enforcement', parameters('vnetEncryptionEnforcement')), null())]", - "flowTimeoutInMinutes": "[if(not(equals(parameters('flowTimeoutInMinutes'), 0)), parameters('flowTimeoutInMinutes'), null())]", - "enableVmProtection": "[parameters('enableVmProtection')]" - } - }, - "virtualNetwork_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/virtualNetworks/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_diagnosticSettings": { - "copy": { - "name": "virtualNetwork_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_roleAssignments": { - "copy": { - "name": "virtualNetwork_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks', 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": [ - "virtualNetwork" - ] - }, - "virtualNetwork_subnets": { - "copy": { - "name": "virtualNetwork_subnets", - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-subnet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualNetworkName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('subnets'), createArray())[copyIndex()].name]" - }, - "addressPrefix": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefix')]" - }, - "addressPrefixes": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'addressPrefixes')]" - }, - "applicationGatewayIPConfigurations": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'applicationGatewayIPConfigurations')]" - }, - "delegation": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'delegation')]" - }, - "natGatewayResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'natGatewayResourceId')]" - }, - "networkSecurityGroupResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'networkSecurityGroupResourceId')]" - }, - "privateEndpointNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateEndpointNetworkPolicies')]" - }, - "privateLinkServiceNetworkPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'privateLinkServiceNetworkPolicies')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "routeTableResourceId": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'routeTableResourceId')]" - }, - "serviceEndpointPolicies": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpointPolicies')]" - }, - "serviceEndpoints": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'serviceEndpoints')]" - }, - "defaultOutboundAccess": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'defaultOutboundAccess')]" - }, - "sharingScope": { - "value": "[tryGet(coalesce(parameters('subnets'), createArray())[copyIndex()], 'sharingScope')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "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.34.1.11899", - "templateHash": "2692730101868032103" - }, - "name": "Virtual Network Subnets", - "description": "This module deploys a Virtual Network Subnet." - }, - "definitions": { - "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.2.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The Name of the subnet resource." - } - }, - "virtualNetworkName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual network. Required if the template is used in a standalone deployment." - } - }, - "addressPrefix": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the network security group to assign to the subnet." - } - }, - "routeTableResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the route table to assign to the subnet." - } - }, - "serviceEndpoints": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. The service endpoints to enable on the subnet." - } - }, - "delegation": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The delegation to enable on the subnet." - } - }, - "natGatewayResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the NAT Gateway to use for the subnet." - } - }, - "privateEndpointNetworkPolicies": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled", - "NetworkSecurityGroupEnabled", - "RouteTableEnabled" - ], - "metadata": { - "description": "Optional. Enable or disable apply network policies on private endpoint in the subnet." - } - }, - "privateLinkServiceNetworkPolicies": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Disabled", - "Enabled" - ], - "metadata": { - "description": "Optional. Enable or disable apply network policies on private link service in the subnet." - } - }, - "addressPrefixes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty." - } - }, - "defaultOutboundAccess": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet." - } - }, - "sharingScope": { - "type": "string", - "allowedValues": [ - "DelegatedServices", - "Tenant" - ], - "nullable": true, - "metadata": { - "description": "Optional. Set this property to Tenant to allow sharing the subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if the subnet is empty." - } - }, - "applicationGatewayIPConfigurations": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Application gateway IP configurations of virtual network resource." - } - }, - "serviceEndpointPolicies": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An array of service endpoint policies." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "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')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-virtualnetworksubnet.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name), 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" - } - } - } - } - }, - "virtualNetwork": { - "existing": true, - "type": "Microsoft.Network/virtualNetworks", - "apiVersion": "2024-01-01", - "name": "[parameters('virtualNetworkName')]" - }, - "subnet": { - "type": "Microsoft.Network/virtualNetworks/subnets", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('virtualNetworkName'), parameters('name'))]", - "properties": { - "copy": [ - { - "name": "serviceEndpoints", - "count": "[length(parameters('serviceEndpoints'))]", - "input": { - "service": "[parameters('serviceEndpoints')[copyIndex('serviceEndpoints')]]" - } - } - ], - "addressPrefix": "[parameters('addressPrefix')]", - "addressPrefixes": "[parameters('addressPrefixes')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]", - "routeTable": "[if(not(empty(parameters('routeTableResourceId'))), createObject('id', parameters('routeTableResourceId')), null())]", - "natGateway": "[if(not(empty(parameters('natGatewayResourceId'))), createObject('id', parameters('natGatewayResourceId')), null())]", - "delegations": "[if(not(empty(parameters('delegation'))), createArray(createObject('name', parameters('delegation'), 'properties', createObject('serviceName', parameters('delegation')))), createArray())]", - "privateEndpointNetworkPolicies": "[parameters('privateEndpointNetworkPolicies')]", - "privateLinkServiceNetworkPolicies": "[parameters('privateLinkServiceNetworkPolicies')]", - "applicationGatewayIPConfigurations": "[parameters('applicationGatewayIPConfigurations')]", - "serviceEndpointPolicies": "[parameters('serviceEndpointPolicies')]", - "defaultOutboundAccess": "[parameters('defaultOutboundAccess')]", - "sharingScope": "[parameters('sharingScope')]" - } - }, - "subnet_roleAssignments": { - "copy": { - "name": "subnet_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/virtualNetworks/{0}/subnets/{1}', parameters('virtualNetworkName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), 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": [ - "subnet" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/subnets', parameters('virtualNetworkName'), parameters('name'))]" - }, - "addressPrefix": { - "type": "string", - "metadata": { - "description": "The address prefix for the subnet." - }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefix'), '')]" - }, - "addressPrefixes": { - "type": "array", - "metadata": { - "description": "List of address prefixes for the subnet." - }, - "value": "[coalesce(tryGet(reference('subnet'), 'addressPrefixes'), createArray())]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualNetwork_peering_local": { - "copy": { - "name": "virtualNetwork_peering_local", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-virtualNetworkPeering-local-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "localVnetName": { - "value": "[parameters('name')]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'name')]" - }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowForwardedTraffic')]" - }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowGatewayTransit')]" - }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'allowVirtualNetworkAccess')]" - }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'doNotVerifyRemoteGateways')]" - }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'useRemoteGateways')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.1.11899", - "templateHash": "7728525434782883754" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." - } - }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", - "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" - ] - }, - "virtualNetwork_peering_remote": { - "copy": { - "name": "virtualNetwork_peering_remote", - "count": "[length(coalesce(parameters('peerings'), createArray()))]" - }, - "condition": "[coalesce(tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringEnabled'), false())]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-virtualNetworkPeering-remote-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "subscriptionId": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[2]]", - "resourceGroup": "[split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "localVnetName": { - "value": "[last(split(coalesce(parameters('peerings'), createArray())[copyIndex()].remoteVirtualNetworkResourceId, '/'))]" - }, - "remoteVirtualNetworkResourceId": { - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringName')]" - }, - "allowForwardedTraffic": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowForwardedTraffic')]" - }, - "allowGatewayTransit": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowGatewayTransit')]" - }, - "allowVirtualNetworkAccess": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringAllowVirtualNetworkAccess')]" - }, - "doNotVerifyRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringDoNotVerifyRemoteGateways')]" - }, - "useRemoteGateways": { - "value": "[tryGet(coalesce(parameters('peerings'), createArray())[copyIndex()], 'remotePeeringUseRemoteGateways')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.1.11899", - "templateHash": "7728525434782883754" - }, - "name": "Virtual Network Peerings", - "description": "This module deploys a Virtual Network Peering." - }, - "parameters": { - "name": { - "type": "string", - "defaultValue": "[format('peer-{0}-{1}', parameters('localVnetName'), last(split(parameters('remoteVirtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The Name of VNET Peering resource. If not provided, default value will be localVnetName-remoteVnetName." - } - }, - "localVnetName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Virtual Network to add the peering to. Required if the template is used in a standalone deployment." - } - }, - "remoteVirtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The Resource ID of the VNet that is this Local VNet is being peered to. Should be in the format of a Resource ID." - } - }, - "allowForwardedTraffic": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the forwarded traffic from the VMs in the local virtual network will be allowed/disallowed in remote virtual network. Default is true." - } - }, - "allowGatewayTransit": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If gateway links can be used in remote virtual networking to link to this virtual network. Default is false." - } - }, - "allowVirtualNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether the VMs in the local virtual network space would be able to access the VMs in remote virtual network space. Default is true." - } - }, - "doNotVerifyRemoteGateways": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If we need to verify the provisioning state of the remote gateway. Default is true." - } - }, - "useRemoteGateways": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If remote gateways can be used on this virtual network. If the flag is set to true, and allowGatewayTransit on remote peering is also true, virtual network will use gateways of remote virtual network for transit. Only one peering can have this flag set to true. This flag cannot be set if virtual network already has a gateway. Default is false." - } - } - }, - "resources": [ - { - "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", - "apiVersion": "2024-01-01", - "name": "[format('{0}/{1}', parameters('localVnetName'), parameters('name'))]", - "properties": { - "allowForwardedTraffic": "[parameters('allowForwardedTraffic')]", - "allowGatewayTransit": "[parameters('allowGatewayTransit')]", - "allowVirtualNetworkAccess": "[parameters('allowVirtualNetworkAccess')]", - "doNotVerifyRemoteGateways": "[parameters('doNotVerifyRemoteGateways')]", - "useRemoteGateways": "[parameters('useRemoteGateways')]", - "remoteVirtualNetwork": { - "id": "[parameters('remoteVirtualNetworkResourceId')]" - } - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network peering was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network peering." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network peering." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks/virtualNetworkPeerings', parameters('localVnetName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork", - "virtualNetwork_subnets" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the virtual network was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the virtual network." - }, - "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the virtual network." - }, - "value": "[parameters('name')]" - }, - "subnetNames": { - "type": "array", - "metadata": { - "description": "The names of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.name.value]" - } - }, - "subnetResourceIds": { - "type": "array", - "metadata": { - "description": "The resource IDs of the deployed subnets." - }, - "copy": { - "count": "[length(coalesce(parameters('subnets'), createArray()))]", - "input": "[reference(format('virtualNetwork_subnets[{0}]', copyIndex())).outputs.resourceId.value]" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetwork', '2024-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "networkSecurityGroupAdministration", - "networkSecurityGroupBackend", - "networkSecurityGroupBastion", - "networkSecurityGroupContainers" - ] - }, - "bastionHost": { - "condition": "[and(variables('virtualNetworkEnabled'), variables('bastionEnabled'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.bastion-host.{0}', variables('bastionResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('bastionResourceName')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('bastionConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "skuName": { - "value": "[coalesce(tryGet(parameters('bastionConfiguration'), 'sku'), 'Standard')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('bastionConfiguration'), 'tags'), parameters('tags'))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(tryGet(parameters('bastionConfiguration'), 'virtualNetworkResourceId'), tryGet(tryGet(tryGet(reference('virtualNetwork'), 'outputs'), 'resourceId'), 'value'))]" - }, - "publicIPAddressObject": { - "value": { - "name": "[coalesce(tryGet(parameters('bastionConfiguration'), 'publicIpResourceName'), format('pip-bas{0}', parameters('solutionPrefix')))]", - "zones": [] - } - }, - "disableCopyPaste": { - "value": false - }, - "enableFileCopy": { - "value": false - }, - "enableIpConnect": { - "value": true - }, - "enableShareableLink": { - "value": true - } - }, - "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.33.93.31351", - "templateHash": "2586599138991803385" - }, - "name": "Bastion Hosts", - "description": "This module deploys a Bastion Host." - }, - "definitions": { - "diagnosticSettingLogsOnlyType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "logAnalyticsDestinationType": { - "type": "string", - "allowedValues": [ - "AzureDiagnostics", - "Dedicated" - ], - "nullable": true, - "metadata": { - "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." - } - }, - "workspaceResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "eventHubAuthorizationRuleResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." - } - }, - "eventHubName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." - } - }, - "marketplacePartnerResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Azure Bastion resource." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Shared services Virtual Network resource Id." - } - }, - "bastionSubnetPublicIpResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The Public IP resource ID to associate to the azureBastionSubnet. If empty, then the Public IP that is created as part of this module will be applied to the azureBastionSubnet. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "publicIPAddressObject": { - "type": "object", - "defaultValue": { - "name": "[format('{0}-pip', parameters('name'))]" - }, - "metadata": { - "description": "Optional. Specifies the properties of the Public IP to create and be used by Azure Bastion, if no existing public IP was provided. This parameter is ignored when enablePrivateOnlyBastion is true." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingLogsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Basic", - "allowedValues": [ - "Basic", - "Developer", - "Premium", - "Standard" - ], - "metadata": { - "description": "Optional. The SKU of this Bastion Host." - } - }, - "disableCopyPaste": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Copy Paste. For Basic and Developer SKU Copy/Paste is always enabled." - } - }, - "enableFileCopy": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Choose to disable or enable File Copy. Not supported for Basic and Developer SKU." - } - }, - "enableIpConnect": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable IP Connect. Not supported for Basic and Developer SKU." - } - }, - "enableKerberos": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Kerberos authentication. Not supported for Developer SKU." - } - }, - "enableShareableLink": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Shareable Link. Not supported for Basic and Developer SKU." - } - }, - "enableSessionRecording": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Session Recording feature. The Premium SKU is required for this feature. If Session Recording is enabled, the Native client support will be disabled." - } - }, - "enablePrivateOnlyBastion": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Choose to disable or enable Private-only Bastion deployment. The Premium SKU is required for this feature." - } - }, - "scaleUnits": { - "type": "int", - "defaultValue": 2, - "metadata": { - "description": "Optional. The scale units for the Bastion Host resource. The Basic and Developer SKU only support 2 scale units." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting where the Bastion Host resource needs to come from. This is not supported for the Developer SKU." - } - } - }, - "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)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-bastionhost.{0}.{1}', replace('0.6.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" - } - } - } - } - }, - "azureBastion": { - "type": "Microsoft.Network/bastionHosts", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[coalesce(parameters('tags'), createObject())]", - "sku": { - "name": "[parameters('skuName')]" - }, - "zones": "[if(equals(parameters('skuName'), 'Developer'), createArray(), map(parameters('zones'), lambda('zone', string(lambdaVariables('zone')))))]", - "properties": "[union(createObject('scaleUnits', if(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Developer')), 2, parameters('scaleUnits')), 'ipConfigurations', if(equals(parameters('skuName'), 'Developer'), createArray(), createArray(createObject('name', 'IpConfAzureBastionSubnet', 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureBastionSubnet', parameters('virtualNetworkResourceId')))), if(not(parameters('enablePrivateOnlyBastion')), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('bastionSubnetPublicIpResourceId'))), parameters('bastionSubnetPublicIpResourceId'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))))), if(equals(parameters('skuName'), 'Developer'), createObject('virtualNetwork', createObject('id', parameters('virtualNetworkResourceId'))), createObject()), if(or(or(equals(parameters('skuName'), 'Basic'), equals(parameters('skuName'), 'Standard')), equals(parameters('skuName'), 'Premium')), createObject('enableKerberos', parameters('enableKerberos')), createObject()), if(or(equals(parameters('skuName'), 'Standard'), equals(parameters('skuName'), 'Premium')), createObject('enableTunneling', if(equals(parameters('skuName'), 'Standard'), true(), if(parameters('enableSessionRecording'), false(), true())), 'disableCopyPaste', parameters('disableCopyPaste'), 'enableFileCopy', parameters('enableFileCopy'), 'enableIpConnect', parameters('enableIpConnect'), 'enableShareableLink', parameters('enableShareableLink')), createObject()), if(equals(parameters('skuName'), 'Premium'), createObject('enableSessionRecording', parameters('enableSessionRecording'), 'enablePrivateOnlyBastion', parameters('enablePrivateOnlyBastion')), createObject()))]", - "dependsOn": [ - "publicIPAddress" - ] - }, - "azureBastion_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/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_diagnosticSettings": { - "copy": { - "name": "azureBastion_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "azureBastion" - ] - }, - "azureBastion_roleAssignments": { - "copy": { - "name": "azureBastion_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/bastionHosts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/bastionHosts', 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": [ - "azureBastion" - ] - }, - "publicIPAddress": { - "condition": "[and(and(empty(parameters('bastionSubnetPublicIpResourceId')), not(equals(parameters('skuName'), 'Developer'))), not(parameters('enablePrivateOnlyBastion')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Bastion-PIP', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('publicIPAddressObject').name]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'diagnosticSettings')]" - }, - "publicIPAddressVersion": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAddressVersion')]" - }, - "publicIPAllocationMethod": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPAllocationMethod')]" - }, - "publicIpPrefixResourceId": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'publicIPPrefixResourceId')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'roleAssignments')]" - }, - "skuName": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuName')]" - }, - "skuTier": { - "value": "[tryGet(parameters('publicIPAddressObject'), 'skuTier')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'tags'), parameters('tags'))]" - }, - "zones": { - "value": "[coalesce(tryGet(parameters('publicIPAddressObject'), 'zones'), if(greater(length(parameters('zones')), 0), parameters('zones'), null()))]" - } - }, - "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.33.93.31351", - "templateHash": "5168739580767459761" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address." - }, - "definitions": { - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "nullable": true, - "metadata": { - "description": "Optional. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipTagType": { - "type": "object", - "properties": { - "ipTagType": { - "type": "string", - "metadata": { - "description": "Required. The IP tag type." - } - }, - "tag": { - "type": "string", - "metadata": { - "description": "Required. The IP tag." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.2.1" - } - } - }, - "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." - } - } - }, - "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.2.1" - } - } - }, - "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.2.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "ipTags": { - "type": "array", - "items": { - "$ref": "#/definitions/ipTagType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of tags associated with the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.8.0', '.', '-'), 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" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2024-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": "[parameters('ipTags')]" - } - }, - "publicIpAddress_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/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', 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": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2024-05-01', 'full').location]" - } - } - } - } - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the Azure Bastion was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name the Azure Bastion." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID the Azure Bastion." - }, - "value": "[resourceId('Microsoft.Network/bastionHosts', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('azureBastion', '2024-05-01', 'full').location]" - }, - "ipConfAzureBastionSubnet": { - "type": "object", - "metadata": { - "description": "The Public IPconfiguration object for the AzureBastionSubnet." - }, - "value": "[if(equals(parameters('skuName'), 'Developer'), createObject(), reference('azureBastion').ipConfigurations[0])]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "virtualMachine": { - "condition": "[and(variables('virtualNetworkEnabled'), variables('virtualMachineEnabled'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.compute.virtual-machine.{0}', variables('virtualMachineResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('virtualMachineResourceName')]" - }, - "computerName": { - "value": "[take(variables('virtualMachineResourceName'), 15)]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "vmSize": { - "value": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'vmSize'), 'Standard_D2s_v3')]" - }, - "adminUsername": { - "value": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'adminUsername'), 'adminuser')]" - }, - "adminPassword": { - "value": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'adminPassword'), guid(parameters('solutionPrefix'), subscription().subscriptionId))]" - }, - "nicConfigurations": { - "value": [ - { - "name": "[format('nic-{0}', variables('virtualMachineResourceName'))]", - "diagnosticSettings": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ], - "ipConfigurations": [ - { - "name": "[format('{0}-nic01-ipconfig01', variables('virtualMachineResourceName'))]", - "subnetResourceId": "[coalesce(tryGet(parameters('virtualMachineConfiguration'), 'subnetResourceId'), reference('virtualNetwork').outputs.subnetResourceIds.value[1])]", - "diagnosticSettings": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - } - ] - } - ] - }, - "imageReference": { - "value": { - "publisher": "microsoft-dsvm", - "offer": "dsvm-win-2022", - "sku": "winserver-2022", - "version": "latest" - } - }, - "osDisk": { - "value": { - "name": "[format('osdisk-{0}', variables('virtualMachineResourceName'))]", - "createOption": "FromImage", - "managedDisk": { - "storageAccountType": "Standard_LRS" - }, - "diskSizeGB": 128, - "caching": "ReadWrite" - } - }, - "osType": { - "value": "Windows" - }, - "encryptionAtHost": { - "value": false - }, - "zone": { - "value": 0 - }, - "extensionAadJoinConfig": { - "value": { - "enabled": true, - "typeHandlerVersion": "1.0" - } - } - }, - "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.34.44.8038", - "templateHash": "13105916093025105823" - }, - "name": "Virtual Machines", - "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs." - }, - "definitions": { - "osDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "diskSizeGB": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "diffDiskSettings": { - "type": "object", - "properties": { - "placement": { - "type": "string", - "allowedValues": [ - "CacheDisk", - "NvmeDisk", - "ResourceDisk" - ], - "metadata": { - "description": "Required. Specifies the ephemeral disk placement for the operating system disk." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the ephemeral Disk Settings for the operating system disk." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing an OS disk." - } - }, - "dataDiskType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The disk name." - } - }, - "lun": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the logical unit number of the data disk." - } - }, - "diskSizeGB": { - "type": "int", - "metadata": { - "description": "Required. Specifies the size of an empty data disk in gigabytes." - } - }, - "createOption": { - "type": "string", - "allowedValues": [ - "Attach", - "Empty", - "FromImage" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies how the virtual machine should be created." - } - }, - "deleteOption": { - "type": "string", - "allowedValues": [ - "Delete", - "Detach" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies whether data disk should be deleted or detached upon VM deletion." - } - }, - "caching": { - "type": "string", - "allowedValues": [ - "None", - "ReadOnly", - "ReadWrite" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specifies the caching requirements." - } - }, - "diskIOPSReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The number of IOPS allowed for this disk; only settable for UltraSSD disks. One operation can transfer between 4k and 256k bytes." - } - }, - "diskMBpsReadWrite": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The bandwidth allowed for this disk; only settable for UltraSSD disks. MBps means millions of bytes per second - MB here uses the ISO notation, of powers of 10." - } - }, - "managedDisk": { - "type": "object", - "properties": { - "storageAccountType": { - "type": "string", - "allowedValues": [ - "PremiumV2_LRS", - "Premium_LRS", - "Premium_ZRS", - "StandardSSD_LRS", - "StandardSSD_ZRS", - "Standard_LRS", - "UltraSSD_LRS" - ], - "metadata": { - "description": "Required. Specifies the storage account type for the managed disk." - } - }, - "diskEncryptionSetResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk encryption set resource id for the managed disk." - } - }, - "id": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the customer managed disk id for the managed disk." - } - } - }, - "metadata": { - "description": "Required. The managed disk parameters." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type describing a data disk." - } - }, - "publicKeyType": { - "type": "object", - "properties": { - "keyData": { - "type": "string", - "metadata": { - "description": "Required. Specifies the SSH public key data used to authenticate through ssh." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Specifies the full path on the created VM where ssh public key is stored. If the file already exists, the specified key is appended to the file." - } - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine to be created. You should use a unique prefix to reduce name collisions in Active Directory." - } - }, - "computerName": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. Can be used if the computer name needs to be different from the Azure VM resource name. If not used, the resource name will be used as computer name." - } - }, - "vmSize": { - "type": "string", - "metadata": { - "description": "Required. Specifies the size for the VMs." - } - }, - "encryptionAtHost": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. This property can be used by user in the request to enable or disable the Host Encryption for the virtual machine. This will enable the encryption for all the disks including Resource/Temp disk at host itself. For security reasons, it is recommended to set encryptionAtHost to True. Restrictions: Cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "securityType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "", - "ConfidentialVM", - "TrustedLaunch" - ], - "metadata": { - "description": "Optional. Specifies the SecurityType of the virtual machine. It has to be set to any specified value to enable UefiSettings. The default behavior is: UefiSettings will not be enabled unless this property is set." - } - }, - "secureBootEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether secure boot should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "vTpmEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether vTPM should be enabled on the virtual machine. This parameter is part of the UefiSettings. SecurityType should be set to TrustedLaunch to enable UefiSettings." - } - }, - "imageReference": { - "type": "object", - "metadata": { - "description": "Required. OS image reference. In case of marketplace images, it's the combination of the publisher, offer, sku, version attributes. In case of custom images it's the resource ID of the custom image." - } - }, - "plan": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Specifies information about the marketplace image used to create the virtual machine. This element is only used for marketplace images. Before you can use a marketplace image from an API, you must enable the image for programmatic use." - } - }, - "osDisk": { - "$ref": "#/definitions/osDiskType", - "metadata": { - "description": "Required. Specifies the OS disk. For security reasons, it is recommended to specify DiskEncryptionSet into the osDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "dataDisks": { - "type": "array", - "items": { - "$ref": "#/definitions/dataDiskType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the data disks. For security reasons, it is recommended to specify DiskEncryptionSet into the dataDisk object. Restrictions: DiskEncryptionSet cannot be enabled if Azure Disk Encryption (guest-VM encryption using bitlocker/DM-Crypt) is enabled on your VMs." - } - }, - "ultraSSDEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag that enables or disables a capability to have one or more managed data disks with UltraSSD_LRS storage account type on the VM or VMSS. Managed disks with storage account type UltraSSD_LRS can be added to a virtual machine or virtual machine scale set only if this property is enabled." - } - }, - "adminUsername": { - "type": "securestring", - "metadata": { - "description": "Required. Administrator username." - } - }, - "adminPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. When specifying a Windows Virtual Machine, this value should be passed." - } - }, - "userData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. UserData for the VM, which must be base-64 encoded. Customer should not pass any secrets in here." - } - }, - "customData": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom data associated to the VM, this value will be automatically converted into base64 to account for the expected VM format." - } - }, - "certificatesToBeInstalled": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies set of certificates that should be installed onto the virtual machine." - } - }, - "priority": { - "type": "string", - "defaultValue": "Regular", - "allowedValues": [ - "Regular", - "Low", - "Spot" - ], - "metadata": { - "description": "Optional. Specifies the priority for the virtual machine." - } - }, - "evictionPolicy": { - "type": "string", - "defaultValue": "Deallocate", - "allowedValues": [ - "Deallocate", - "Delete" - ], - "metadata": { - "description": "Optional. Specifies the eviction policy for the low priority virtual machine." - } - }, - "maxPriceForLowPriorityVm": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the maximum price you are willing to pay for a low priority VM/VMSS. This price is in US Dollars." - } - }, - "dedicatedHostId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies resource ID about the dedicated host that the virtual machine resides in." - } - }, - "licenseType": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "RHEL_BYOS", - "SLES_BYOS", - "Windows_Client", - "Windows_Server", - "" - ], - "metadata": { - "description": "Optional. Specifies that the image or disk that is being used was licensed on-premises." - } - }, - "publicKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/publicKeyType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. The list of SSH public keys used to authenticate with linux based VMs." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource. The system-assigned managed identity will automatically be enabled if extensionAadJoinConfig.enabled = \"True\"." - } - }, - "bootDiagnostics": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Whether boot diagnostics should be enabled on the Virtual Machine. Boot diagnostics will be enabled with a managed storage account if no bootDiagnosticsStorageAccountName value is provided. If bootDiagnostics and bootDiagnosticsStorageAccountName values are not provided, boot diagnostics will be disabled." - } - }, - "bootDiagnosticStorageAccountName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Custom storage account used to store boot diagnostic information. Boot diagnostics will be enabled with a custom storage account if a value is provided." - } - }, - "bootDiagnosticStorageAccountUri": { - "type": "string", - "defaultValue": "[format('.blob.{0}/', environment().suffixes.storage)]", - "metadata": { - "description": "Optional. Storage account boot diagnostic base URI." - } - }, - "proximityPlacementGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a proximity placement group." - } - }, - "virtualMachineScaleSetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of a virtual machine scale set, where the VM should be added." - } - }, - "availabilitySetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Resource ID of an availability set. Cannot be used in combination with availability zone nor scale set." - } - }, - "galleryApplications": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies the gallery applications that should be made available to the VM/VMSS." - } - }, - "zone": { - "type": "int", - "allowedValues": [ - 0, - 1, - 2, - 3 - ], - "metadata": { - "description": "Required. If set to 1, 2 or 3, the availability zone for all VMs is hardcoded to that value. If zero, then availability zones is not used. Cannot be used in combination with availability set nor scale set." - } - }, - "nicConfigurations": { - "type": "array", - "metadata": { - "description": "Required. Configures NICs and PIPs." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Recovery service vault name to add VMs to backup." - } - }, - "backupVaultResourceGroup": { - "type": "string", - "defaultValue": "[resourceGroup().name]", - "metadata": { - "description": "Optional. Resource group of the backup recovery service vault. If not provided the current resource group name is considered by default." - } - }, - "backupPolicyName": { - "type": "string", - "defaultValue": "DefaultPolicy", - "metadata": { - "description": "Optional. Backup policy the VMs should be using for backup. If not provided, it will use the DefaultPolicy from the backup recovery service vault." - } - }, - "autoShutdownConfig": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for auto-shutdown." - } - }, - "maintenanceConfigurationResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The resource Id of a maintenance configuration for this VM." - } - }, - "allowExtensionOperations": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Specifies whether extension operations should be allowed on the virtual machine. This may only be set to False when no extensions are present on the virtual machine." - } - }, - "extensionDomainJoinPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Required if name is specified. Password of the user specified in user parameter." - } - }, - "extensionDomainJoinConfig": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. The configuration for the [Domain Join] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAadJoinConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [AAD Join] extension. Must at least contain the [\"enabled\": true] property to be executed. To enroll in Intune, add the setting mdmId: \"0000000a-0000-0000-c000-000000000000\"." - } - }, - "extensionAntiMalwareConfig": { - "type": "object", - "defaultValue": "[if(equals(parameters('osType'), 'Windows'), createObject('enabled', true()), createObject('enabled', false()))]", - "metadata": { - "description": "Optional. The configuration for the [Anti Malware] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionMonitoringAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "dataCollectionRuleAssociations": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Monitoring Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionDependencyAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Dependency Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNetworkWatcherAgentConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Network Watcher Agent] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionAzureDiskEncryptionConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Azure Disk Encryption] extension. Must at least contain the [\"enabled\": true] property to be executed. Restrictions: Cannot be enabled on disks that have encryption at host enabled. Managed disks encrypted using Azure Disk Encryption cannot be encrypted using customer-managed keys." - } - }, - "extensionDSCConfig": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Desired State Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionCustomScriptConfig": { - "type": "object", - "defaultValue": { - "enabled": false, - "fileData": [] - }, - "metadata": { - "description": "Optional. The configuration for the [Custom Script] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionNvidiaGpuDriverWindows": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Nvidia Gpu Driver Windows] extension. Must at least contain the [\"enabled\": true] property to be executed." - } - }, - "extensionHostPoolRegistration": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Host Pool Registration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identy." - } - }, - "extensionGuestConfigurationExtension": { - "type": "object", - "defaultValue": { - "enabled": false - }, - "metadata": { - "description": "Optional. The configuration for the [Guest Configuration] extension. Must at least contain the [\"enabled\": true] property to be executed. Needs a managed identy." - } - }, - "guestConfiguration": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The guest configuration for the virtual machine. Needs the Guest Configuration extension to be enabled." - } - }, - "extensionCustomScriptProtectedSetting": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "extensionGuestConfigurationExtensionProtectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. An object that contains the extension specific protected settings." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "baseTime": { - "type": "string", - "defaultValue": "[utcNow('u')]", - "metadata": { - "description": "Generated. Do not provide a value! This date value is used to generate a registration token." - } - }, - "sasTokenValidityLength": { - "type": "string", - "defaultValue": "PT8H", - "metadata": { - "description": "Optional. SAS token validity length to use to download files from storage accounts. Usage: 'PT8H' - valid for 8 hours; 'P5D' - valid for 5 days; 'P1Y' - valid for 1 year. When not provided, the SAS token will be valid for 8 hours." - } - }, - "osType": { - "type": "string", - "allowedValues": [ - "Windows", - "Linux" - ], - "metadata": { - "description": "Required. The chosen OS type." - } - }, - "disablePasswordAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Specifies whether password authentication should be disabled." - } - }, - "provisionVMAgent": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether virtual machine agent should be provisioned on the virtual machine. When this property is not specified in the request body, default behavior is to set it to true. This will ensure that VM Agent is installed on the VM so that extensions can be added to the VM later." - } - }, - "enableAutomaticUpdates": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates whether Automatic Updates is enabled for the Windows virtual machine. Default value is true. When patchMode is set to Manual, this parameter must be set to false. For virtual machine scale sets, this property can be updated and updates will take effect on OS reprovisioning." - } - }, - "patchMode": { - "type": "string", - "defaultValue": "", - "allowedValues": [ - "AutomaticByPlatform", - "AutomaticByOS", - "Manual", - "ImageDefault", - "" - ], - "metadata": { - "description": "Optional. VM guest patching orchestration mode. 'AutomaticByOS' & 'Manual' are for Windows only, 'ImageDefault' for Linux only. Refer to 'https://learn.microsoft.com/en-us/azure/virtual-machines/automatic-vm-guest-patching'." - } - }, - "bypassPlatformSafetyChecksOnUserSchedule": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enables customer to schedule patching without accidental upgrades." - } - }, - "rebootSetting": { - "type": "string", - "defaultValue": "IfRequired", - "allowedValues": [ - "Always", - "IfRequired", - "Never", - "Unknown" - ], - "metadata": { - "description": "Optional. Specifies the reboot setting for all AutomaticByPlatform patch installation operations." - } - }, - "patchAssessmentMode": { - "type": "string", - "defaultValue": "ImageDefault", - "allowedValues": [ - "AutomaticByPlatform", - "ImageDefault" - ], - "metadata": { - "description": "Optional. VM guest patching assessment mode. Set it to 'AutomaticByPlatform' to enable automatically check for updates every 24 hours." - } - }, - "enableHotpatching": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Enables customers to patch their Azure VMs without requiring a reboot. For enableHotpatching, the 'provisionVMAgent' must be set to true and 'patchMode' must be set to 'AutomaticByPlatform'." - } - }, - "timeZone": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Specifies the time zone of the virtual machine. e.g. 'Pacific Standard Time'. Possible values can be `TimeZoneInfo.id` value from time zones returned by `TimeZoneInfo.GetSystemTimeZones`." - } - }, - "additionalUnattendContent": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies additional XML formatted information that can be included in the Unattend.xml file, which is used by Windows Setup. Contents are defined by setting name, component name, and the pass in which the content is applied." - } - }, - "winRM": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Specifies the Windows Remote Management listeners. This enables remote Windows PowerShell. - WinRMConfiguration object." - } - }, - "configurationProfile": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The configuration profile of automanage. Either '/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction', 'providers/Microsoft.Automanage/bestPractices/AzureBestPracticesDevTest' or the resource Id of custom profile." - } - } - }, - "variables": { - "copy": [ - { - "name": "publicKeysFormatted", - "count": "[length(parameters('publicKeys'))]", - "input": { - "path": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].path]", - "keyData": "[parameters('publicKeys')[copyIndex('publicKeysFormatted')].keyData]" - } - }, - { - "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)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "linuxConfiguration": { - "disablePasswordAuthentication": "[parameters('disablePasswordAuthentication')]", - "ssh": { - "publicKeys": "[variables('publicKeysFormatted')]" - }, - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('ImageDefault')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]" - }, - "windowsConfiguration": { - "provisionVMAgent": "[parameters('provisionVMAgent')]", - "enableAutomaticUpdates": "[parameters('enableAutomaticUpdates')]", - "patchSettings": "[if(and(parameters('provisionVMAgent'), or(or(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), equals(toLower(parameters('patchMode')), toLower('AutomaticByOS'))), equals(toLower(parameters('patchMode')), toLower('Manual')))), createObject('patchMode', parameters('patchMode'), 'assessmentMode', parameters('patchAssessmentMode'), 'enableHotpatching', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), parameters('enableHotpatching'), false()), 'automaticByPlatformSettings', if(equals(toLower(parameters('patchMode')), toLower('AutomaticByPlatform')), createObject('bypassPlatformSafetyChecksOnUserSchedule', parameters('bypassPlatformSafetyChecksOnUserSchedule'), 'rebootSetting', parameters('rebootSetting')), null())), null())]", - "timeZone": "[if(empty(parameters('timeZone')), null(), parameters('timeZone'))]", - "additionalUnattendContent": "[if(empty(parameters('additionalUnattendContent')), null(), parameters('additionalUnattendContent'))]", - "winRM": "[if(not(empty(parameters('winRM'))), createObject('listeners', parameters('winRM')), null())]" - }, - "accountSasProperties": { - "signedServices": "b", - "signedPermission": "r", - "signedExpiry": "[dateTimeAdd(parameters('baseTime'), parameters('sasTokenValidityLength'))]", - "signedResourceTypes": "o", - "signedProtocol": "https" - }, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", - "Desktop Virtualization Power On Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '489581de-a3bd-480d-9518-53dea7416b33')]", - "Desktop Virtualization Power On Off Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '40c5ff49-9181-41f8-ae61-143b0e78555e')]", - "Desktop Virtualization Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a959dbd1-f747-45e3-8ba6-dd80f235f97c')]", - "DevTest Labs User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '76283e04-6283-4c54-8f91-bcf1374a3c64')]", - "Disk Backup Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3e5e47e6-65f7-47ef-90b5-e5dd4d455f24')]", - "Disk Pool Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '60fc6e62-5479-42d4-8bf4-67625fcc2840')]", - "Disk Restore Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b50d9833-a0cb-478e-945f-707fcc997c13')]", - "Disk Snapshot Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7efff54f-a5b4-42b5-a1c5-5411624893ce')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Virtual Machine Administrator Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1c0163c0-47e6-4577-8991-ea5c82e286e4')]", - "Virtual Machine Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9980e02c-c2be-4d73-94e8-173b1dc7cf3c')]", - "Virtual Machine User Login": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb879df8-f326-4884-b1cf-06f3ad86be52')]", - "VM Scanner Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd24ecba3-c1f4-40fa-a7bb-4588a071e8fd')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.compute-virtualmachine.{0}.{1}', replace('0.13.0', '.', '-'), 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" - } - } - } - } - }, - "managedDataDisks": { - "copy": { - "name": "managedDataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]" - }, - "type": "Microsoft.Compute/disks", - "apiVersion": "2024-03-02", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex(), 1), 2, '0')))]", - "location": "[parameters('location')]", - "sku": { - "name": "[coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk.storageAccountType]" - }, - "properties": { - "diskSizeGB": "[coalesce(parameters('dataDisks'), createArray())[copyIndex()].diskSizeGB]", - "creationData": { - "createOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'createoption'), 'Empty')]" - }, - "diskIOPSReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskIOPSReadWrite')]", - "diskMBpsReadWrite": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex()], 'diskMBpsReadWrite')]" - }, - "zones": "[if(and(not(equals(parameters('zone'), 0)), not(contains(coalesce(parameters('dataDisks'), createArray())[copyIndex()].managedDisk.storageAccountType, 'ZRS'))), array(string(parameters('zone'))), null())]" - }, - "vm": { - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2024-07-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "tags": "[parameters('tags')]", - "zones": "[if(not(equals(parameters('zone'), 0)), array(string(parameters('zone'))), null())]", - "plan": "[if(not(empty(parameters('plan'))), parameters('plan'), null())]", - "properties": { - "hardwareProfile": { - "vmSize": "[parameters('vmSize')]" - }, - "securityProfile": { - "encryptionAtHost": "[if(parameters('encryptionAtHost'), parameters('encryptionAtHost'), null())]", - "securityType": "[parameters('securityType')]", - "uefiSettings": "[if(equals(parameters('securityType'), 'TrustedLaunch'), createObject('secureBootEnabled', parameters('secureBootEnabled'), 'vTpmEnabled', parameters('vTpmEnabled')), null())]" - }, - "storageProfile": { - "copy": [ - { - "name": "dataDisks", - "count": "[length(coalesce(parameters('dataDisks'), createArray()))]", - "input": { - "lun": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'lun'), copyIndex('dataDisks'))]", - "name": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))]", - "diskSizeGB": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].diskSizeGB]", - "createOption": "[if(not(equals(resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0')))), null())), 'Attach', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'createoption'), 'Empty'))]", - "deleteOption": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'deleteOption'), 'Delete')]", - "caching": "[coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk.storageAccountType]", - "id": "[resourceId('Microsoft.Compute/disks', coalesce(tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')], 'name'), format('{0}-disk-data-{1}', parameters('name'), padLeft(add(copyIndex('dataDisks'), 1), 2, '0'))))]", - "diskEncryptionSet": { - "id": "[tryGet(coalesce(parameters('dataDisks'), createArray())[copyIndex('dataDisks')].managedDisk, 'diskEncryptionSetResourceId')]" - } - } - } - } - ], - "imageReference": "[parameters('imageReference')]", - "osDisk": { - "name": "[coalesce(tryGet(parameters('osDisk'), 'name'), format('{0}-disk-os-01', parameters('name')))]", - "createOption": "[coalesce(tryGet(parameters('osDisk'), 'createOption'), 'FromImage')]", - "deleteOption": "[coalesce(tryGet(parameters('osDisk'), 'deleteOption'), 'Delete')]", - "diffDiskSettings": "[if(empty(coalesce(tryGet(parameters('osDisk'), 'diffDiskSettings'), createObject())), null(), createObject('option', 'Local', 'placement', parameters('osDisk').diffDiskSettings.placement))]", - "diskSizeGB": "[parameters('osDisk').diskSizeGB]", - "caching": "[coalesce(tryGet(parameters('osDisk'), 'caching'), 'ReadOnly')]", - "managedDisk": { - "storageAccountType": "[parameters('osDisk').managedDisk.storageAccountType]", - "diskEncryptionSet": { - "id": "[tryGet(parameters('osDisk').managedDisk, 'diskEncryptionSetResourceId')]" - } - } - } - }, - "additionalCapabilities": { - "ultraSSDEnabled": "[parameters('ultraSSDEnabled')]" - }, - "osProfile": { - "computerName": "[parameters('computerName')]", - "adminUsername": "[parameters('adminUsername')]", - "adminPassword": "[parameters('adminPassword')]", - "customData": "[if(not(empty(parameters('customData'))), base64(parameters('customData')), null())]", - "windowsConfiguration": "[if(equals(parameters('osType'), 'Windows'), variables('windowsConfiguration'), null())]", - "linuxConfiguration": "[if(equals(parameters('osType'), 'Linux'), variables('linuxConfiguration'), null())]", - "secrets": "[parameters('certificatesToBeInstalled')]", - "allowExtensionOperations": "[parameters('allowExtensionOperations')]" - }, - "networkProfile": { - "copy": [ - { - "name": "networkInterfaces", - "count": "[length(parameters('nicConfigurations'))]", - "input": { - "properties": { - "deleteOption": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'deleteOption'), 'Delete')]", - "primary": "[if(equals(copyIndex('networkInterfaces'), 0), true(), false())]" - }, - "id": "[resourceId('Microsoft.Network/networkInterfaces', coalesce(tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex('networkInterfaces')], 'nicSuffix'))))]" - } - } - ] - }, - "diagnosticsProfile": { - "bootDiagnostics": { - "enabled": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), true(), parameters('bootDiagnostics'))]", - "storageUri": "[if(not(empty(parameters('bootDiagnosticStorageAccountName'))), format('https://{0}{1}', parameters('bootDiagnosticStorageAccountName'), parameters('bootDiagnosticStorageAccountUri')), null())]" - } - }, - "applicationProfile": "[if(not(empty(parameters('galleryApplications'))), createObject('galleryApplications', parameters('galleryApplications')), null())]", - "availabilitySet": "[if(not(empty(parameters('availabilitySetResourceId'))), createObject('id', parameters('availabilitySetResourceId')), null())]", - "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", - "virtualMachineScaleSet": "[if(not(empty(parameters('virtualMachineScaleSetResourceId'))), createObject('id', parameters('virtualMachineScaleSetResourceId')), null())]", - "priority": "[parameters('priority')]", - "evictionPolicy": "[if(not(equals('Regular', parameters('priority'))), parameters('evictionPolicy'), null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", - "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", - "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]", - "userData": "[if(not(empty(parameters('userData'))), base64(parameters('userData')), null())]" - }, - "dependsOn": [ - "managedDataDisks", - "vm_nic" - ] - }, - "vm_configurationAssignment": { - "condition": "[not(empty(parameters('maintenanceConfigurationResourceId')))]", - "type": "Microsoft.Maintenance/configurationAssignments", - "apiVersion": "2023-04-01", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "[format('{0}assignment', parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "maintenanceConfigurationId": "[parameters('maintenanceConfigurationResourceId')]", - "resourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_configurationProfileAssignment": { - "condition": "[not(empty(parameters('configurationProfile')))]", - "type": "Microsoft.Automanage/configurationProfileAssignments", - "apiVersion": "2022-05-04", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "default", - "properties": { - "configurationProfile": "[parameters('configurationProfile')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_autoShutdownConfiguration": { - "condition": "[not(empty(parameters('autoShutdownConfig')))]", - "type": "Microsoft.DevTestLab/schedules", - "apiVersion": "2018-09-15", - "name": "[format('shutdown-computevm-{0}', parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "status": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'status'), 'Disabled')]", - "targetResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]", - "taskType": "ComputeVmShutdownTask", - "dailyRecurrence": { - "time": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'dailyRecurrenceTime'), '19:00')]" - }, - "timeZoneId": "[coalesce(tryGet(parameters('autoShutdownConfig'), 'timeZone'), 'UTC')]", - "notificationSettings": "[if(contains(parameters('autoShutdownConfig'), 'notificationStatus'), createObject('status', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationStatus'), 'Disabled'), 'emailRecipient', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationEmail'), ''), 'notificationLocale', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationLocale'), 'en'), 'webhookUrl', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationWebhookUrl'), ''), 'timeInMinutes', coalesce(tryGet(parameters('autoShutdownConfig'), 'notificationTimeInMinutes'), 30)), null())]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_dataCollectionRuleAssociations": { - "copy": { - "name": "vm_dataCollectionRuleAssociations", - "count": "[length(parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations)]" - }, - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Insights/dataCollectionRuleAssociations", - "apiVersion": "2023-03-11", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].name]", - "properties": { - "dataCollectionRuleId": "[parameters('extensionMonitoringAgentConfig').dataCollectionRuleAssociations[copyIndex()].dataCollectionRuleResourceId]" - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "AzureWindowsBaseline": { - "condition": "[not(empty(parameters('guestConfiguration')))]", - "type": "Microsoft.GuestConfiguration/guestConfigurationAssignments", - "apiVersion": "2020-06-25", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "AzureWindowsBaseline", - "location": "[parameters('location')]", - "properties": { - "guestConfiguration": "[parameters('guestConfiguration')]" - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - }, - "vm_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.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "vm" - ] - }, - "vm_roleAssignments": { - "copy": { - "name": "vm_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Compute/virtualMachines/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Compute/virtualMachines', 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": [ - "vm" - ] - }, - "vm_nic": { - "copy": { - "name": "vm_nic", - "count": "[length(parameters('nicConfigurations'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-Nic-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "networkInterfaceName": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'name'), format('{0}{1}', parameters('name'), tryGet(parameters('nicConfigurations')[copyIndex()], 'nicSuffix')))]" - }, - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "enableIPForwarding": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableIPForwarding'), false())]" - }, - "enableAcceleratedNetworking": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'enableAcceleratedNetworking'), true())]" - }, - "dnsServers": "[if(contains(parameters('nicConfigurations')[copyIndex()], 'dnsServers'), if(not(empty(parameters('nicConfigurations')[copyIndex()].dnsServers)), createObject('value', parameters('nicConfigurations')[copyIndex()].dnsServers), createObject('value', createArray())), createObject('value', createArray()))]", - "networkSecurityGroupResourceId": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'networkSecurityGroupResourceId'), '')]" - }, - "ipConfigurations": { - "value": "[parameters('nicConfigurations')[copyIndex()].ipConfigurations]" - }, - "lock": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'lock'), parameters('lock'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('nicConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(parameters('nicConfigurations')[copyIndex()], 'roleAssignments')]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - } - }, - "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.34.44.8038", - "templateHash": "8556043111080362230" - } - }, - "definitions": { - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "networkInterfaceName": { - "type": "string" - }, - "virtualMachineName": { - "type": "string" - }, - "ipConfigurations": { - "type": "array" - }, - "location": { - "type": "string", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false - }, - "dnsServers": { - "type": "array", - "defaultValue": [] - }, - "enableTelemetry": { - "type": "bool", - "metadata": { - "description": "Required. Enable telemetry via a Globally Unique Identifier (GUID)." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "resources": { - "networkInterface_publicIPAddresses": { - "copy": { - "name": "networkInterface_publicIPAddresses", - "count": "[length(parameters('ipConfigurations'))]" - }, - "condition": "[and(contains(parameters('ipConfigurations')[copyIndex()], 'pipConfiguration'), not(contains(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-publicIP-{1}', deployment().name, copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIpNameSuffix')))]" - }, - "diagnosticSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()], 'diagnosticSettings')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "idleTimeoutInMinutes": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'idleTimeoutInMinutes')]" - }, - "ddosSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'ddosSettings')]" - }, - "dnsSettings": { - "value": "[tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'dnsSettings')]" - }, - "publicIPAddressVersion": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAddressVersion'), 'IPv4')]" - }, - "publicIPAllocationMethod": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPAllocationMethod'), 'Static')]" - }, - "publicIpPrefixResourceId": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'publicIPPrefixResourceId'), '')]" - }, - "roleAssignments": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'roleAssignments'), createArray())]" - }, - "skuName": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuName'), 'Standard')]" - }, - "skuTier": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'skuTier'), 'Regional')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "zones": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()].pipConfiguration, 'zones'), createArray(1, 2, 3))]" - }, - "enableTelemetry": { - "value": "[coalesce(tryGet(parameters('ipConfigurations')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" - } - }, - "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.29.47.4906", - "templateHash": "16693645977675862540" - }, - "name": "Public IP Addresses", - "description": "This module deploys a Public IP Address.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "dnsSettingsType": { - "type": "object", - "properties": { - "domainNameLabel": { - "type": "string", - "metadata": { - "description": "Required. The domain name label. The concatenation of the domain name label and the regionalized DNS zone make up the fully qualified domain name associated with the public IP address. If a domain name label is specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system." - } - }, - "domainNameLabelScope": { - "type": "string", - "allowedValues": [ - "", - "NoReuse", - "ResourceGroupReuse", - "SubscriptionReuse", - "TenantReuse" - ], - "metadata": { - "description": "Required. The domain name label scope. If a domain name label and a domain name label scope are specified, an A DNS record is created for the public IP in the Microsoft Azure DNS system with a hashed value includes in FQDN." - } - }, - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Fully Qualified Domain Name of the A DNS record associated with the public IP. This is the concatenation of the domainNameLabel and the regionalized DNS zone." - } - }, - "reverseFqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The reverse FQDN. A user-visible, fully qualified domain name that resolves to this public IP address. If the reverseFqdn is specified, then a PTR DNS record is created pointing from the IP address in the in-addr.arpa domain to the reverse FQDN." - } - } - } - }, - "ddosSettingsType": { - "type": "object", - "properties": { - "ddosProtectionPlan": { - "type": "object", - "properties": { - "id": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the DDOS protection plan associated with the public IP address." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan associated with the public IP address." - } - }, - "protectionMode": { - "type": "string", - "allowedValues": [ - "Enabled" - ], - "metadata": { - "description": "Required. The DDoS protection policy customizations." - } - } - } - }, - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the Public IP Address." - } - }, - "publicIpPrefixResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the Public IP Prefix object. This is only needed if you want your Public IPs created in a PIP Prefix." - } - }, - "publicIPAllocationMethod": { - "type": "string", - "defaultValue": "Static", - "allowedValues": [ - "Dynamic", - "Static" - ], - "metadata": { - "description": "Optional. The public IP address allocation method." - } - }, - "zones": { - "type": "array", - "items": { - "type": "int" - }, - "defaultValue": [ - 1, - 2, - 3 - ], - "allowedValues": [ - 1, - 2, - 3 - ], - "metadata": { - "description": "Optional. A list of availability zones denoting the IP allocated for the resource needs to come from." - } - }, - "publicIPAddressVersion": { - "type": "string", - "defaultValue": "IPv4", - "allowedValues": [ - "IPv4", - "IPv6" - ], - "metadata": { - "description": "Optional. IP address version." - } - }, - "dnsSettings": { - "$ref": "#/definitions/dnsSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DNS settings of the public IP address." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "skuName": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Basic", - "Standard" - ], - "metadata": { - "description": "Optional. Name of a public IP address SKU." - } - }, - "skuTier": { - "type": "string", - "defaultValue": "Regional", - "allowedValues": [ - "Global", - "Regional" - ], - "metadata": { - "description": "Optional. Tier of a public IP address SKU." - } - }, - "ddosSettings": { - "$ref": "#/definitions/ddosSettingsType", - "nullable": true, - "metadata": { - "description": "Optional. The DDoS protection plan configuration associated with the public IP address." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "idleTimeoutInMinutes": { - "type": "int", - "defaultValue": 4, - "metadata": { - "description": "Optional. The idle timeout of the public IP address." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), 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" - } - } - } - } - }, - "publicIpAddress": { - "type": "Microsoft.Network/publicIPAddresses", - "apiVersion": "2023-09-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "tier": "[parameters('skuTier')]" - }, - "zones": "[map(parameters('zones'), lambda('zone', string(lambdaVariables('zone'))))]", - "properties": { - "ddosSettings": "[parameters('ddosSettings')]", - "dnsSettings": "[parameters('dnsSettings')]", - "publicIPAddressVersion": "[parameters('publicIPAddressVersion')]", - "publicIPAllocationMethod": "[parameters('publicIPAllocationMethod')]", - "publicIPPrefix": "[if(not(empty(parameters('publicIpPrefixResourceId'))), createObject('id', parameters('publicIpPrefixResourceId')), null())]", - "idleTimeoutInMinutes": "[parameters('idleTimeoutInMinutes')]", - "ipTags": null - } - }, - "publicIpAddress_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/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - }, - "publicIpAddress_roleAssignments": { - "copy": { - "name": "publicIpAddress_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/publicIPAddresses', 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": [ - "publicIpAddress" - ] - }, - "publicIpAddress_diagnosticSettings": { - "copy": { - "name": "publicIpAddress_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/publicIPAddresses/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "publicIpAddress" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the public IP address was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the public IP address." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the public IP address." - }, - "value": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('name'))]" - }, - "ipAddress": { - "type": "string", - "metadata": { - "description": "The public IP address of the public IP address resource." - }, - "value": "[coalesce(tryGet(reference('publicIpAddress'), 'ipAddress'), '')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('publicIpAddress', '2023-09-01', 'full').location]" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-NetworkInterface', deployment().name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('networkInterfaceName')]" - }, - "ipConfigurations": { - "copy": [ - { - "name": "value", - "count": "[length(parameters('ipConfigurations'))]", - "input": "[createObject('name', if(not(empty(parameters('ipConfigurations')[copyIndex('value')].name)), parameters('ipConfigurations')[copyIndex('value')].name, null()), 'primary', equals(copyIndex('value'), 0), 'privateIPAllocationMethod', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('value')].privateIPAllocationMethod, null()), null()), 'privateIPAddress', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('value')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('value')].privateIPAddress, null()), null()), 'publicIPAddressResourceId', if(contains(parameters('ipConfigurations')[copyIndex('value')], 'pipConfiguration'), if(not(contains(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'publicIPAddressResourceId')), resourceId('Microsoft.Network/publicIPAddresses', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'name'), format('{0}{1}', parameters('virtualMachineName'), tryGet(parameters('ipConfigurations')[copyIndex('value')].pipConfiguration, 'publicIpNameSuffix')))), parameters('ipConfigurations')[copyIndex('value')].pipConfiguration.publicIPAddressResourceId), null()), 'subnetResourceId', parameters('ipConfigurations')[copyIndex('value')].subnetResourceId, 'loadBalancerBackendAddressPools', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerBackendAddressPools'), null()), 'applicationSecurityGroups', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationSecurityGroups'), null()), 'applicationGatewayBackendAddressPools', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'applicationGatewayBackendAddressPools'), null()), 'gatewayLoadBalancer', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'gatewayLoadBalancer'), null()), 'loadBalancerInboundNatRules', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'loadBalancerInboundNatRules'), null()), 'privateIPAddressVersion', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'privateIPAddressVersion'), null()), 'virtualNetworkTaps', coalesce(tryGet(parameters('ipConfigurations')[copyIndex('value')], 'virtualNetworkTaps'), null()))]" - } - ] - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "dnsServers": "[if(not(empty(parameters('dnsServers'))), createObject('value', parameters('dnsServers')), createObject('value', createArray()))]", - "enableAcceleratedNetworking": { - "value": "[parameters('enableAcceleratedNetworking')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "enableIPForwarding": { - "value": "[parameters('enableIPForwarding')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "networkSecurityGroupResourceId": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('value', parameters('networkSecurityGroupResourceId')), createObject('value', ''))]", - "roleAssignments": "[if(not(empty(parameters('roleAssignments'))), createObject('value', parameters('roleAssignments')), createObject('value', createArray()))]" - }, - "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.29.47.4906", - "templateHash": "9226998037927576702" - }, - "name": "Network Interface", - "description": "This module deploys a Network Interface.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "diagnosticSettingType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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." - } - } - } - }, - "nullable": true - }, - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the network interface." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "enableIPForwarding": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether IP forwarding is enabled on this network interface." - } - }, - "enableAcceleratedNetworking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the network interface is accelerated networking enabled." - } - }, - "dnsServers": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of DNS servers IP addresses. Use 'AzureProvidedDNS' to switch to azure provided DNS resolution. 'AzureProvidedDNS' value cannot be combined with other IPs, it must be the only value in dnsServers collection." - } - }, - "networkSecurityGroupResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. The network security group (NSG) to attach to the network interface." - } - }, - "auxiliaryMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "Floating", - "MaxConnections", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary mode of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "auxiliarySku": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "A1", - "A2", - "A4", - "A8", - "None" - ], - "metadata": { - "description": "Optional. Auxiliary sku of Network Interface resource. Not all regions are enabled for Auxiliary Mode Nic." - } - }, - "disableTcpStateTracking": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether to disable tcp state tracking. Subscription must be registered for the Microsoft.Network/AllowDisableTcpStateTracking feature before this property can be set to true." - } - }, - "ipConfigurations": { - "type": "array", - "metadata": { - "description": "Required. A list of IPConfigurations of the network interface." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "$ref": "#/definitions/diagnosticSettingType", - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "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')]", - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-networkinterface.{0}.{1}', replace('0.4.0', '.', '-'), 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" - } - } - } - } - }, - "networkInterface": { - "type": "Microsoft.Network/networkInterfaces", - "apiVersion": "2023-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "ipConfigurations", - "count": "[length(parameters('ipConfigurations'))]", - "input": { - "name": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'name'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].name, format('ipconfig0{0}', add(copyIndex('ipConfigurations'), 1)))]", - "properties": { - "primary": "[if(equals(copyIndex('ipConfigurations'), 0), true(), false())]", - "privateIPAllocationMethod": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAllocationMethod'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAllocationMethod, null()), null())]", - "privateIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddress'), if(not(empty(parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress)), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddress, null()), null())]", - "publicIPAddress": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'publicIPAddressResourceId'), if(not(equals(parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId, null())), createObject('id', parameters('ipConfigurations')[copyIndex('ipConfigurations')].publicIPAddressResourceId), null()), null())]", - "subnet": { - "id": "[parameters('ipConfigurations')[copyIndex('ipConfigurations')].subnetResourceId]" - }, - "loadBalancerBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerBackendAddressPools, null())]", - "applicationSecurityGroups": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationSecurityGroups'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationSecurityGroups, null())]", - "applicationGatewayBackendAddressPools": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'applicationGatewayBackendAddressPools'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].applicationGatewayBackendAddressPools, null())]", - "gatewayLoadBalancer": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'gatewayLoadBalancer'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].gatewayLoadBalancer, null())]", - "loadBalancerInboundNatRules": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'loadBalancerInboundNatRules'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].loadBalancerInboundNatRules, null())]", - "privateIPAddressVersion": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'privateIPAddressVersion'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].privateIPAddressVersion, null())]", - "virtualNetworkTaps": "[if(contains(parameters('ipConfigurations')[copyIndex('ipConfigurations')], 'virtualNetworkTaps'), parameters('ipConfigurations')[copyIndex('ipConfigurations')].virtualNetworkTaps, null())]" - } - } - } - ], - "auxiliaryMode": "[parameters('auxiliaryMode')]", - "auxiliarySku": "[parameters('auxiliarySku')]", - "disableTcpStateTracking": "[parameters('disableTcpStateTracking')]", - "dnsSettings": "[if(not(empty(parameters('dnsServers'))), createObject('dnsServers', parameters('dnsServers')), null())]", - "enableAcceleratedNetworking": "[parameters('enableAcceleratedNetworking')]", - "enableIPForwarding": "[parameters('enableIPForwarding')]", - "networkSecurityGroup": "[if(not(empty(parameters('networkSecurityGroupResourceId'))), createObject('id', parameters('networkSecurityGroupResourceId')), null())]" - } - }, - "networkInterface_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/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_diagnosticSettings": { - "copy": { - "name": "networkInterface_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "networkInterface" - ] - }, - "networkInterface_roleAssignments": { - "copy": { - "name": "networkInterface_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/networkInterfaces/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/networkInterfaces', 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": [ - "networkInterface" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed resource." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed resource." - }, - "value": "[resourceId('Microsoft.Network/networkInterfaces', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed resource." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('networkInterface', '2023-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "networkInterface_publicIPAddresses" - ] - } - } - } - } - }, - "vm_aadJoinExtension": { - "condition": "[parameters('extensionAadJoinConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AADLogin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AADLogin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.ActiveDirectory" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AADLoginForWindows'), createObject('value', 'AADSSHLoginforLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAadJoinConfig'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm" - ] - }, - "vm_domainJoinExtension": { - "condition": "[and(contains(parameters('extensionDomainJoinConfig'), 'enabled'), parameters('extensionDomainJoinConfig').enabled)]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DomainJoin', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DomainJoin" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Compute" - }, - "type": { - "value": "JsonADDomainExtension" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[parameters('extensionDomainJoinConfig').settings]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDomainJoinConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": { - "Password": "[parameters('extensionDomainJoinPassword')]" - } - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_aadJoinExtension" - ] - }, - "vm_microsoftAntiMalwareExtension": { - "condition": "[parameters('extensionAntiMalwareConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-MicrosoftAntiMalware', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "MicrosoftAntiMalware" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": { - "value": "IaaSAntimalware" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'typeHandlerVersion'), '1.3')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'settings'), createObject('AntimalwareEnabled', 'true', 'Exclusions', createObject(), 'RealtimeProtectionEnabled', 'true', 'ScheduledScanSettings', createObject('day', '7', 'isEnabled', 'true', 'scanType', 'Quick', 'time', '120')))]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAntiMalwareConfig'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_domainJoinExtension" - ] - }, - "vm_azureMonitorAgentExtension": { - "condition": "[parameters('extensionMonitoringAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AzureMonitorAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AzureMonitorAgent" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitor" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureMonitorWindowsAgent'), createObject('value', 'AzureMonitorLinuxAgent'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.22', '1.29'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionMonitoringAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_microsoftAntiMalwareExtension" - ] - }, - "vm_dependencyAgentExtension": { - "condition": "[parameters('extensionDependencyAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DependencyAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DependencyAgent" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Monitoring.DependencyAgent" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'DependencyAgentWindows'), createObject('value', 'DependencyAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'typeHandlerVersion'), '9.10')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAutomaticUpgrade'), true())]" - }, - "settings": { - "value": { - "enableAMA": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'enableAMA'), true())]" - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDependencyAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureMonitorAgentExtension" - ] - }, - "vm_networkWatcherAgentExtension": { - "condition": "[parameters('extensionNetworkWatcherAgentConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-NetworkWatcherAgent', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "NetworkWatcherAgent" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.NetworkWatcher" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'NetworkWatcherAgentWindows'), createObject('value', 'NetworkWatcherAgentLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNetworkWatcherAgentConfig'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_dependencyAgentExtension" - ] - }, - "vm_desiredStateConfigurationExtension": { - "condition": "[parameters('extensionDSCConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-DesiredStateConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "DesiredStateConfiguration" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Powershell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[coalesce(tryGet(parameters('extensionDSCConfig'), 'protectedSettings'), createObject())]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_networkWatcherAgentExtension" - ] - }, - "vm_customScriptExtension": { - "condition": "[parameters('extensionCustomScriptConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-CustomScriptExtension', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "CustomScriptExtension" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'Microsoft.Compute'), createObject('value', 'Microsoft.Azure.Extensions'))]", - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'CustomScriptExtension'), createObject('value', 'CustomScript'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.10', '2.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": { - "copy": [ - { - "name": "fileUris", - "count": "[length(parameters('extensionCustomScriptConfig').fileData)]", - "input": "[if(contains(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')], 'storageAccountId'), format('{0}?{1}', parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri, listAccountSas(parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].storageAccountId, '2019-04-01', variables('accountSasProperties')).accountSasToken), parameters('extensionCustomScriptConfig').fileData[copyIndex('fileUris')].uri)]" - } - ] - } - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionCustomScriptConfig'), 'tags'), parameters('tags'))]" - }, - "protectedSettings": { - "value": "[parameters('extensionCustomScriptProtectedSetting')]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_desiredStateConfigurationExtension" - ] - }, - "vm_azureDiskEncryptionExtension": { - "condition": "[parameters('extensionAzureDiskEncryptionConfig').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-AzureDiskEncryption', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "AzureDiskEncryption" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.Azure.Security" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzureDiskEncryption'), createObject('value', 'AzureDiskEncryptionForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '2.2', '1.1'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'enableAutomaticUpgrade'), false())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionAzureDiskEncryptionConfig'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_customScriptExtension" - ] - }, - "vm_nvidiaGpuDriverWindowsExtension": { - "condition": "[parameters('extensionNvidiaGpuDriverWindows').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-NvidiaGpuDriverWindows', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "NvidiaGpuDriverWindows" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.HpcCompute" - }, - "type": { - "value": "NvidiaGpuDriverWindows" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'typeHandlerVersion'), '1.4')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'enableAutomaticUpgrade'), false())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'supressFailures'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionNvidiaGpuDriverWindows'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureDiskEncryptionExtension" - ] - }, - "vm_hostPoolRegistrationExtension": { - "condition": "[parameters('extensionHostPoolRegistration').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-HostPoolRegistration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "HostPoolRegistration" - }, - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.PowerShell" - }, - "type": { - "value": "DSC" - }, - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'typeHandlerVersion'), '2.77')]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), false())]" - }, - "settings": { - "value": { - "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", - "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", - "properties": { - "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", - "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]", - "aadJoin": true - }, - "supressFailures": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'supressFailures'), false())]" - } - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_nvidiaGpuDriverWindowsExtension" - ] - }, - "vm_azureGuestConfigurationExtension": { - "condition": "[parameters('extensionGuestConfigurationExtension').enabled]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-GuestConfiguration', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "virtualMachineName": { - "value": "[parameters('name')]" - }, - "name": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'AzurePolicyforWindows'), createObject('value', 'AzurePolicyforLinux'))]", - "location": { - "value": "[parameters('location')]" - }, - "publisher": { - "value": "Microsoft.GuestConfiguration" - }, - "type": "[if(equals(parameters('osType'), 'Windows'), createObject('value', 'ConfigurationforWindows'), createObject('value', 'ConfigurationForLinux'))]", - "typeHandlerVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'typeHandlerVersion'), if(equals(parameters('osType'), 'Windows'), '1.0', '1.0'))]" - }, - "autoUpgradeMinorVersion": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'autoUpgradeMinorVersion'), true())]" - }, - "enableAutomaticUpgrade": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'enableAutomaticUpgrade'), true())]" - }, - "forceUpdateTag": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'forceUpdateTag'), '1.0')]" - }, - "settings": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'settings'), createObject())]" - }, - "supressFailures": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'supressFailures'), false())]" - }, - "protectedSettings": { - "value": "[parameters('extensionGuestConfigurationExtensionProtectedSettings')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('extensionGuestConfigurationExtension'), 'tags'), parameters('tags'))]" - } - }, - "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.34.44.8038", - "templateHash": "8482591295619883067" - }, - "name": "Virtual Machine Extensions", - "description": "This module deploys a Virtual Machine Extension." - }, - "parameters": { - "virtualMachineName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent virtual machine that extension is provisioned for. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the virtual machine extension." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location the extension is deployed to." - } - }, - "publisher": { - "type": "string", - "metadata": { - "description": "Required. The name of the extension handler publisher." - } - }, - "type": { - "type": "string", - "metadata": { - "description": "Required. Specifies the type of the extension; an example is \"CustomScriptExtension\"." - } - }, - "typeHandlerVersion": { - "type": "string", - "metadata": { - "description": "Required. Specifies the version of the script handler." - } - }, - "autoUpgradeMinorVersion": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should use a newer minor version if one is available at deployment time. Once deployed, however, the extension will not upgrade minor versions unless redeployed, even with this property set to true." - } - }, - "forceUpdateTag": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. How the extension handler should be forced to update even if the extension configuration has not changed." - } - }, - "settings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific settings." - } - }, - "protectedSettings": { - "type": "secureObject", - "defaultValue": {}, - "metadata": { - "description": "Optional. Any object that contains the extension specific protected settings." - } - }, - "supressFailures": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Indicates whether failures stemming from the extension will be suppressed (Operational failures such as not connecting to the VM will not be suppressed regardless of this value). The default is false." - } - }, - "enableAutomaticUpgrade": { - "type": "bool", - "metadata": { - "description": "Required. Indicates whether the extension should be automatically upgraded by the platform if there is a newer version of the extension available." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "virtualMachine": { - "existing": true, - "type": "Microsoft.Compute/virtualMachines", - "apiVersion": "2022-11-01", - "name": "[parameters('virtualMachineName')]" - }, - "extension": { - "type": "Microsoft.Compute/virtualMachines/extensions", - "apiVersion": "2022-11-01", - "name": "[format('{0}/{1}', parameters('virtualMachineName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "publisher": "[parameters('publisher')]", - "type": "[parameters('type')]", - "typeHandlerVersion": "[parameters('typeHandlerVersion')]", - "autoUpgradeMinorVersion": "[parameters('autoUpgradeMinorVersion')]", - "enableAutomaticUpgrade": "[parameters('enableAutomaticUpgrade')]", - "forceUpdateTag": "[if(not(empty(parameters('forceUpdateTag'))), parameters('forceUpdateTag'), null())]", - "settings": "[if(not(empty(parameters('settings'))), parameters('settings'), null())]", - "protectedSettings": "[if(not(empty(parameters('protectedSettings'))), parameters('protectedSettings'), null())]", - "suppressFailures": "[parameters('supressFailures')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the extension." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the extension." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('virtualMachineName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the extension was created in." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('extension', '2022-11-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_hostPoolRegistrationExtension" - ] - }, - "vm_backup": { - "condition": "[not(empty(parameters('backupVaultName')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-VM-Backup', uniqueString(deployment().name, parameters('location')))]", - "resourceGroup": "[parameters('backupVaultResourceGroup')]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('vm;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "policyId": { - "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupPolicies', parameters('backupVaultName'), parameters('backupPolicyName'))]" - }, - "protectedItemType": { - "value": "Microsoft.Compute/virtualMachines" - }, - "protectionContainerName": { - "value": "[format('iaasvmcontainer;iaasvmcontainerv2;{0};{1}', resourceGroup().name, parameters('name'))]" - }, - "recoveryVaultName": { - "value": "[parameters('backupVaultName')]" - }, - "sourceResourceId": { - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "7743264001610407207" - }, - "name": "Recovery Service Vaults Protection Container Protected Item", - "description": "This module deploys a Recovery Services Vault Protection Container Protected Item." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the resource." - } - }, - "protectionContainerName": { - "type": "string", - "metadata": { - "description": "Conditional. Name of the Azure Recovery Service Vault Protection Container. Required if the template is used in a standalone deployment." - } - }, - "recoveryVaultName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Azure Recovery Service Vault. Required if the template is used in a standalone deployment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all resources." - } - }, - "protectedItemType": { - "type": "string", - "allowedValues": [ - "AzureFileShareProtectedItem", - "AzureVmWorkloadSAPAseDatabase", - "AzureVmWorkloadSAPHanaDatabase", - "AzureVmWorkloadSQLDatabase", - "DPMProtectedItem", - "GenericProtectedItem", - "MabFileFolderProtectedItem", - "Microsoft.ClassicCompute/virtualMachines", - "Microsoft.Compute/virtualMachines", - "Microsoft.Sql/servers/databases" - ], - "metadata": { - "description": "Required. The backup item type." - } - }, - "policyId": { - "type": "string", - "metadata": { - "description": "Required. ID of the backup policy with which this item is backed up." - } - }, - "sourceResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the resource to back up." - } - } - }, - "resources": [ - { - "type": "Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems", - "apiVersion": "2023-01-01", - "name": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "protectedItemType": "[parameters('protectedItemType')]", - "policyId": "[parameters('policyId')]", - "sourceResourceId": "[parameters('sourceResourceId')]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the Resource Group the protected item was created in." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the protected item." - }, - "value": "[resourceId('Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems', split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[0], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[1], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[2], split(format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name')), '/')[3])]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The Name of the protected item." - }, - "value": "[format('{0}/Azure/{1}/{2}', parameters('recoveryVaultName'), parameters('protectionContainerName'), parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "vm", - "vm_azureGuestConfigurationExtension" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the VM." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the VM." - }, - "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the VM was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('vm', '2024-07-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('vm', '2024-07-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "privateDnsZonesAiServices": { - "copy": { - "name": "privateDnsZonesAiServices", - "count": "[length(objectKeys(variables('openAiPrivateDnsZones')))]" - }, - "condition": "[and(variables('virtualNetworkEnabled'), variables('aiFoundryAIservicesEnabled'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.private-dns-zone.ai-services.{0}.{1}', uniqueString(variables('aiFoundryAiServicesResourceName'), objectKeys(variables('openAiPrivateDnsZones'))[copyIndex()]), parameters('solutionPrefix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[objectKeys(variables('openAiPrivateDnsZones'))[copyIndex()]]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "virtualNetworkLinks": { - "value": [ - { - "name": "[format('vnetlink-{0}', split(objectKeys(variables('openAiPrivateDnsZones'))[copyIndex()], '.')[1])]", - "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" - } - ] - } - }, - "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.34.44.8038", - "templateHash": "4533956061065498344" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone." - }, - "definitions": { - "aType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipv4Address": { - "type": "string", - "metadata": { - "description": "Required. The IPv4 address of this A record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of A records in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the A record." - } - }, - "aaaaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aaaaRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipv6Address": { - "type": "string", - "metadata": { - "description": "Required. The IPv6 address of this AAAA record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of AAAA records in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the AAAA record." - } - }, - "cnameType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "cnameRecord": { - "type": "object", - "properties": { - "cname": { - "type": "string", - "metadata": { - "description": "Required. The canonical name of the CNAME record." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The CNAME record in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the CNAME record." - } - }, - "mxType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "mxRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "exchange": { - "type": "string", - "metadata": { - "description": "Required. The domain name of the mail host for this MX record." - } - }, - "preference": { - "type": "int", - "metadata": { - "description": "Required. The preference value for this MX record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of MX records in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the MX record." - } - }, - "ptrType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "ptrRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ptrdname": { - "type": "string", - "metadata": { - "description": "Required. The PTR target domain name for this PTR record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of PTR records in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the PTR record." - } - }, - "soaType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "soaRecord": { - "type": "object", - "properties": { - "email": { - "type": "string", - "metadata": { - "description": "Required. The email contact for this SOA record." - } - }, - "expireTime": { - "type": "int", - "metadata": { - "description": "Required. The expire time for this SOA record." - } - }, - "host": { - "type": "string", - "metadata": { - "description": "Required. The domain name of the authoritative name server for this SOA record." - } - }, - "minimumTtl": { - "type": "int", - "metadata": { - "description": "Required. The minimum value for this SOA record. By convention this is used to determine the negative caching duration." - } - }, - "refreshTime": { - "type": "int", - "metadata": { - "description": "Required. The refresh value for this SOA record." - } - }, - "retryTime": { - "type": "int", - "metadata": { - "description": "Required. The retry time for this SOA record." - } - }, - "serialNumber": { - "type": "int", - "metadata": { - "description": "Required. The serial number for this SOA record." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The SOA record in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SOA record." - } - }, - "srvType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "srvRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority value for this SRV record." - } - }, - "weight": { - "type": "int", - "metadata": { - "description": "Required. The weight value for this SRV record." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. The port value for this SRV record." - } - }, - "target": { - "type": "string", - "metadata": { - "description": "Required. The target domain name for this SRV record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of SRV records in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SRV record." - } - }, - "txtType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "txtRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The text value of this TXT record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of TXT records in the record set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the TXT record." - } - }, - "virtualNetworkLinkType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 1, - "maxLength": 80, - "metadata": { - "description": "Optional. The resource name." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the virtual network to link." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Region where the resource lives." - } - }, - "registrationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "resolutionPolicy": { - "type": "string", - "allowedValues": [ - "Default", - "NxDomainRedirect" - ], - "nullable": true, - "metadata": { - "description": "Optional. The resolution type of the private-dns-zone fallback machanism." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the virtual network link." - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "a": { - "type": "array", - "items": { - "$ref": "#/definitions/aType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of A records." - } - }, - "aaaa": { - "type": "array", - "items": { - "$ref": "#/definitions/aaaaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of AAAA records." - } - }, - "cname": { - "type": "array", - "items": { - "$ref": "#/definitions/cnameType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of CNAME records." - } - }, - "mx": { - "type": "array", - "items": { - "$ref": "#/definitions/mxType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of MX records." - } - }, - "ptr": { - "type": "array", - "items": { - "$ref": "#/definitions/ptrType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of PTR records." - } - }, - "soa": { - "type": "array", - "items": { - "$ref": "#/definitions/soaType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SOA records." - } - }, - "srv": { - "type": "array", - "items": { - "$ref": "#/definitions/srvType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of SRV records." - } - }, - "txt": { - "type": "array", - "items": { - "$ref": "#/definitions/txtType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of TXT records." - } - }, - "virtualNetworkLinks": { - "type": "array", - "items": { - "$ref": "#/definitions/virtualNetworkLinkType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "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')]", - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.7.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" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_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/privateDnsZones/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_roleAssignments": { - "copy": { - "name": "privateDnsZone_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', 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": [ - "privateDnsZone" - ] - }, - "privateDnsZone_A": { - "copy": { - "name": "privateDnsZone_A", - "count": "[length(coalesce(parameters('a'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" - }, - "aRecords": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "18243374258187942664" - }, - "name": "Private DNS Zone A record", - "description": "This module deploys a Private DNS Zone A record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the A record." - } - }, - "aRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of A records in the record set." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "A": { - "type": "Microsoft.Network/privateDnsZones/A", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aRecords": "[parameters('aRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "A_roleAssignments": { - "copy": { - "name": "A_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/A/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), 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": [ - "A" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed A record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed A record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed A record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_AAAA": { - "copy": { - "name": "privateDnsZone_AAAA", - "count": "[length(coalesce(parameters('aaaa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" - }, - "aaaaRecords": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "7322684246075092047" - }, - "name": "Private DNS Zone AAAA record", - "description": "This module deploys a Private DNS Zone AAAA record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the AAAA record." - } - }, - "aaaaRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of AAAA records in the record set." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "AAAA": { - "type": "Microsoft.Network/privateDnsZones/AAAA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aaaaRecords": "[parameters('aaaaRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "AAAA_roleAssignments": { - "copy": { - "name": "AAAA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/AAAA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), 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": [ - "AAAA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AAAA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed AAAA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed AAAA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_CNAME": { - "copy": { - "name": "privateDnsZone_CNAME", - "count": "[length(coalesce(parameters('cname'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" - }, - "cnameRecord": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "5264706240021075859" - }, - "name": "Private DNS Zone CNAME record", - "description": "This module deploys a Private DNS Zone CNAME record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the CNAME record." - } - }, - "cnameRecord": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A CNAME record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "CNAME": { - "type": "Microsoft.Network/privateDnsZones/CNAME", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "cnameRecord": "[parameters('cnameRecord')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "CNAME_roleAssignments": { - "copy": { - "name": "CNAME_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/CNAME/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), 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": [ - "CNAME" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed CNAME record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed CNAME record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed CNAME record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_MX": { - "copy": { - "name": "privateDnsZone_MX", - "count": "[length(coalesce(parameters('mx'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" - }, - "mxRecords": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "13758189936483275969" - }, - "name": "Private DNS Zone MX record", - "description": "This module deploys a Private DNS Zone MX record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the MX record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "mxRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of MX records in the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "MX": { - "type": "Microsoft.Network/privateDnsZones/MX", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "mxRecords": "[parameters('mxRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "MX_roleAssignments": { - "copy": { - "name": "MX_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/MX/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), 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": [ - "MX" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed MX record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed MX record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed MX record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_PTR": { - "copy": { - "name": "privateDnsZone_PTR", - "count": "[length(coalesce(parameters('ptr'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" - }, - "ptrRecords": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "11955164584650609753" - }, - "name": "Private DNS Zone PTR record", - "description": "This module deploys a Private DNS Zone PTR record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the PTR record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ptrRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of PTR records in the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "PTR": { - "type": "Microsoft.Network/privateDnsZones/PTR", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ptrRecords": "[parameters('ptrRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "PTR_roleAssignments": { - "copy": { - "name": "PTR_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/PTR/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), 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": [ - "PTR" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed PTR record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed PTR record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed PTR record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SOA": { - "copy": { - "name": "privateDnsZone_SOA", - "count": "[length(coalesce(parameters('soa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" - }, - "soaRecord": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "14626715835033259725" - }, - "name": "Private DNS Zone SOA record", - "description": "This module deploys a Private DNS Zone SOA record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SOA record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "soaRecord": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A SOA record." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SOA": { - "type": "Microsoft.Network/privateDnsZones/SOA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "soaRecord": "[parameters('soaRecord')]", - "ttl": "[parameters('ttl')]" - } - }, - "SOA_roleAssignments": { - "copy": { - "name": "SOA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SOA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), 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": [ - "SOA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SOA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SOA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SOA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SRV": { - "copy": { - "name": "privateDnsZone_SRV", - "count": "[length(coalesce(parameters('srv'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" - }, - "srvRecords": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "6510442308165042737" - }, - "name": "Private DNS Zone SRV record", - "description": "This module deploys a Private DNS Zone SRV record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SRV record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "srvRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of SRV records in the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SRV": { - "type": "Microsoft.Network/privateDnsZones/SRV", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "srvRecords": "[parameters('srvRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "SRV_roleAssignments": { - "copy": { - "name": "SRV_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SRV/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), 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": [ - "SRV" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SRV record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SRV record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SRV record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_TXT": { - "copy": { - "name": "privateDnsZone_TXT", - "count": "[length(coalesce(parameters('txt'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" - }, - "txtRecords": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.34.44.8038", - "templateHash": "170623042781622569" - }, - "name": "Private DNS Zone TXT record", - "description": "This module deploys a Private DNS Zone TXT record." - }, - "definitions": { - "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.5.1" - } - } - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the TXT record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "txtRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of TXT records in the record set." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "TXT": { - "type": "Microsoft.Network/privateDnsZones/TXT", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]", - "txtRecords": "[parameters('txtRecords')]" - } - }, - "TXT_roleAssignments": { - "copy": { - "name": "TXT_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), 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": [ - "TXT" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed TXT record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed TXT record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed TXT record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-VNetLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "resolutionPolicy": { - "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" - } - }, - "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.34.44.8038", - "templateHash": "725891200086243555" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link." - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - }, - "resolutionPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." - } - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - }, - "resolutionPolicy": "[parameters('resolutionPolicy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "aiFoundryAiServices": { - "condition": "[variables('aiFoundryAIservicesEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.cognitive-services.account.{0}', variables('aiFoundryAiServicesResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('aiFoundryAiServicesResourceName')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'tags'), parameters('tags'))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'location'), parameters('aiDeploymentsLocation'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "projectName": { - "value": "[format('aifp-{0}', parameters('solutionPrefix'))]" - }, - "projectDescription": { - "value": "[format('aifp-{0}', parameters('solutionPrefix'))]" - }, - "existingFoundryProjectResourceId": { - "value": "[parameters('existingFoundryProjectResourceId')]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "sku": { - "value": "[coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'sku'), 'S0')]" - }, - "kind": { - "value": "AIServices" - }, - "disableLocalAuth": { - "value": true - }, - "customSubDomainName": { - "value": "[variables('aiFoundryAiServicesResourceName')]" - }, - "apiProperties": { - "value": {} - }, - "allowProjectManagement": { - "value": true - }, - "managedIdentities": { - "value": { - "systemAssigned": true - } - }, - "publicNetworkAccess": "[if(variables('virtualNetworkEnabled'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", - "networkAcls": { - "value": { - "bypass": "AzureServices", - "defaultAction": "[if(variables('virtualNetworkEnabled'), 'Deny', 'Allow')]" - } - }, - "privateEndpoints": "[if(and(variables('virtualNetworkEnabled'), not(variables('useExistingFoundryProject'))), createObject('value', createArray(createObject('name', format('pep-{0}', variables('aiFoundryAiServicesResourceName')), 'customNetworkInterfaceName', format('nic-{0}', variables('aiFoundryAiServicesResourceName')), 'subnetResourceId', coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'subnetResourceId'), reference('virtualNetwork').outputs.subnetResourceIds.value[0]), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', map(objectKeys(variables('openAiPrivateDnsZones')), lambda('zone', createObject('name', replace(lambdaVariables('zone'), '.', '-'), 'privateDnsZoneResourceId', resourceId('Microsoft.Network/privateDnsZones', lambdaVariables('zone'))))))))), createObject('value', createArray()))]", - "deployments": { - "value": "[coalesce(tryGet(parameters('aiFoundryAiServicesConfiguration'), 'deployments'), createArray(createObject('name', variables('aiFoundryAiServicesModelDeployment').name, 'model', createObject('format', variables('aiFoundryAiServicesModelDeployment').format, 'name', variables('aiFoundryAiServicesModelDeployment').name, 'version', variables('aiFoundryAiServicesModelDeployment').version), 'raiPolicyName', variables('aiFoundryAiServicesModelDeployment').raiPolicyName, 'sku', createObject('name', variables('aiFoundryAiServicesModelDeployment').sku.name, 'capacity', variables('aiFoundryAiServicesModelDeployment').sku.capacity))))]" - } - }, - "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.1.42791", - "templateHash": "3687921794487882622" - }, - "name": "Cognitive Services", - "description": "This module deploys a Cognitive Service." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "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": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/project.bicep" - } - } - }, - "customerManagedKeyType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." - } - }, - "keyName": { - "type": "string", - "metadata": { - "description": "Required. The name of the customer managed key to use for encryption." - } - }, - "keyVersion": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." - } - }, - "userAssignedIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "projectName": { - "type": "string", - "metadata": { - "description": "Optional: Name for the project which needs to be created." - } - }, - "projectDescription": { - "type": "string", - "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "existingFoundryProjectResourceId": { - "type": "string", - "defaultValue": "" - }, - "kind": { - "type": "string", - "allowedValues": [ - "AIServices", - "AnomalyDetector", - "CognitiveServices", - "ComputerVision", - "ContentModerator", - "ContentSafety", - "ConversationalLanguageUnderstanding", - "CustomVision.Prediction", - "CustomVision.Training", - "Face", - "FormRecognizer", - "HealthInsights", - "ImmersiveReader", - "Internal.AllInOne", - "LUIS", - "LUIS.Authoring", - "LanguageAuthoring", - "MetricsAdvisor", - "OpenAI", - "Personalizer", - "QnAMaker.v2", - "SpeechServices", - "TextAnalytics", - "TextTranslation" - ], - "metadata": { - "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "sku": { - "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." - } - }, - "customSubDomainName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. Subdomain name used for token-based authentication. Required if 'networkAcls' or 'privateEndpoints' are set." - } - }, - "networkAcls": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A collection of rules governing the accessibility from specific network locations." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "allowedFqdnList": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. List of allowed FQDN." - } - }, - "apiProperties": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The API properties for special APIs." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Allow only Azure AD authentication. Should be enabled for security reasons." - } - }, - "customerManagedKey": { - "$ref": "#/definitions/customerManagedKeyType", - "nullable": true, - "metadata": { - "description": "Optional. The customer managed key definition." - } - }, - "dynamicThrottlingEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. The flag to enable dynamic throttling." - } - }, - "migrationToken": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. Resource migration token." - } - }, - "restore": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Restore a soft-deleted cognitive service at deployment time. Will fail if no such soft-deleted resource exists." - } - }, - "restrictOutboundNetworkAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Restrict outbound network access." - } - }, - "userOwnedStorage": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The storage accounts for this resource." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "allowProjectManagement": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable project management feature for AI Foundry." - } - } - }, - "variables": { - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "useExistingService": "[not(empty(parameters('existingFoundryProjectResourceId')))]", - "existingCognitiveServiceDetails": "[split(parameters('existingFoundryProjectResourceId'), '/')]" - }, - "resources": { - "cMKKeyVault::cMKKey": { - "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults/keys", - "apiVersion": "2023-07-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.cognitiveservices-account.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "cMKKeyVault": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-07-01", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" - }, - "cMKUserAssignedIdentity": { - "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", - "existing": true, - "type": "Microsoft.ManagedIdentity/userAssignedIdentities", - "apiVersion": "2025-01-31-preview", - "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", - "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", - "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" - }, - "cognitiveServiceNew": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-04-01-preview", - "name": "[parameters('name')]", - "kind": "[parameters('kind')]", - "identity": "[variables('identity')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('sku')]" - }, - "properties": { - "allowProjectManagement": "[parameters('allowProjectManagement')]", - "customSubDomainName": "[parameters('customSubDomainName')]", - "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", - "publicNetworkAccess": "[if(not(equals(parameters('publicNetworkAccess'), null())), parameters('publicNetworkAccess'), if(not(empty(parameters('networkAcls'))), 'Enabled', 'Disabled'))]", - "allowedFqdnList": "[parameters('allowedFqdnList')]", - "apiProperties": "[parameters('apiProperties')]", - "disableLocalAuth": "[parameters('disableLocalAuth')]", - "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.KeyVault', 'keyVaultProperties', createObject('identityClientId', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), tryGet(parameters('customerManagedKey'), 'keyVersion'), last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null())]", - "migrationToken": "[parameters('migrationToken')]", - "restore": "[parameters('restore')]", - "restrictOutboundNetworkAccess": "[parameters('restrictOutboundNetworkAccess')]", - "userOwnedStorage": "[parameters('userOwnedStorage')]", - "dynamicThrottlingEnabled": "[parameters('dynamicThrottlingEnabled')]" - }, - "dependsOn": [ - "cMKKeyVault", - "cMKKeyVault::cMKKey", - "cMKUserAssignedIdentity" - ] - }, - "cognitiveServiceExisting": { - "condition": "[variables('useExistingService')]", - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-04-01-preview", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", - "name": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "cognigive_service_dependencies": { - "condition": "[not(variables('useExistingService'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('cognigive_service_dependencies-{0}', uniqueString('cognigive_service_dependencies', deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "deployments": { - "value": "[parameters('deployments')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" - }, - "sku": { - "value": "[parameters('sku')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "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.1.42791", - "templateHash": "4128376395637895528" - } - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "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": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "sku": { - "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "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." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "projectName": { - "type": "string", - "metadata": { - "description": "Optional: Name for the project which needs to be created." - } - }, - "projectDescription": { - "type": "string", - "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" - } - } - }, - "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": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-04-01-preview", - "name": "[parameters('name')]" - }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-04-01-preview", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" - }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" - }, - "cognitiveService_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.CognitiveServices/accounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - } - }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - } - }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', 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')]" - } - }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "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.5.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": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "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." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), 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-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(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": "2022-09-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.34.44.8038", - "templateHash": "13997305779829540948" - }, - "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 - } - } - }, - "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." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } - } - }, - "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-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "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))]" - } - } - } - } - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key2)), createArray()))]" - } - }, - "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.1.42791", - "templateHash": "1200612323329026557" - } - }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-07-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } - } - } - } - } - }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" - } - }, - "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.1.42791", - "templateHash": "125568697111155565" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services project." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. The location of the Project resource." - } - }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } - }, - "aiServicesName": { - "type": "string", - "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" - } - } - }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2024-10-01", - "name": "[parameters('aiServicesName')]" - }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-04-01-preview", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" - } - } - }, - "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." - }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } - } - } - } - } - } - }, - "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" - } - } - } - }, - "dependsOn": [ - "cognitiveServiceNew" - ] - }, - "existing_cognigive_service_dependencies": { - "condition": "[variables('useExistingService')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('existing_cognigive_service_dependencies-{0}', uniqueString('existing_cognigive_service_dependencies', deployment().name))]", - "subscriptionId": "[variables('existingCognitiveServiceDetails')[2]]", - "resourceGroup": "[variables('existingCognitiveServiceDetails')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('existingCognitiveServiceDetails')[8]]" - }, - "projectName": { - "value": "[parameters('projectName')]" - }, - "projectDescription": { - "value": "[parameters('projectDescription')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('existingFoundryProjectResourceId')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "deployments": { - "value": "[parameters('deployments')]" - }, - "diagnosticSettings": { - "value": "[parameters('diagnosticSettings')]" - }, - "lock": { - "value": "[parameters('lock')]" - }, - "privateEndpoints": { - "value": "[parameters('privateEndpoints')]" - }, - "roleAssignments": { - "value": "[parameters('roleAssignments')]" - }, - "secretsExportConfiguration": { - "value": "[parameters('secretsExportConfiguration')]" - }, - "sku": { - "value": "[parameters('sku')]" - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "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.1.42791", - "templateHash": "4128376395637895528" - } - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "deploymentType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of cognitive service account deployment." - } - }, - "model": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account deployment model." - } - }, - "format": { - "type": "string", - "metadata": { - "description": "Required. The format of Cognitive Services account deployment model." - } - }, - "version": { - "type": "string", - "metadata": { - "description": "Required. The version of Cognitive Services account deployment model." - } - } - }, - "metadata": { - "description": "Required. Properties of Cognitive Services account deployment model." - } - }, - "sku": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource model definition representing SKU." - } - }, - "capacity": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The capacity of the resource model definition representing SKU." - } - }, - "tier": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The tier of the resource model definition representing SKU." - } - }, - "size": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The size of the resource model definition representing SKU." - } - }, - "family": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The family of the resource model definition representing SKU." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource model definition representing SKU." - } - }, - "raiPolicyName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of RAI policy." - } - }, - "versionUpgradeOption": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The version upgrade option." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account deployment." - } - }, - "endpointType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Type of the endpoint." - } - }, - "endpoint": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The endpoint URI." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a cognitive services account endpoint." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The key vault name where to store the keys and connection strings generated by the modules." - } - }, - "accessKey1Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey1 secret to create." - } - }, - "accessKey2Name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name for the accessKey2 secret to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the secrets exported to the provided Key Vault." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "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": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "description": "Output type representing AI project information.", - "__bicep_imported_from!": { - "sourceTemplate": "project.bicep" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/_1.secretSetOutputType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "description": "A map of the exported secrets", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of Cognitive Services account." - } - }, - "sku": { - "type": "string", - "defaultValue": "S0", - "allowedValues": [ - "C2", - "C3", - "C4", - "F0", - "F1", - "S", - "S0", - "S1", - "S10", - "S2", - "S3", - "S4", - "S5", - "S6", - "S7", - "S8", - "S9" - ], - "metadata": { - "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "deployments": { - "type": "array", - "items": { - "$ref": "#/definitions/deploymentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of deployments about cognitive service accounts to create." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "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." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "projectName": { - "type": "string", - "metadata": { - "description": "Optional: Name for the project which needs to be created." - } - }, - "projectDescription": { - "type": "string", - "metadata": { - "description": "Optional: Description for the project which needs to be created." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional: Provide the existing project resource id in case if it needs to be reused" - } - } - }, - "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": { - "Cognitive Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68')]", - "Cognitive Services Custom Vision Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3')]", - "Cognitive Services Custom Vision Deployment": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5c4089e1-6d96-4d2f-b296-c1bc7137275f')]", - "Cognitive Services Custom Vision Labeler": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '88424f51-ebe7-446f-bc41-7fa16989e96c')]", - "Cognitive Services Custom Vision Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '93586559-c37d-4a6b-ba08-b9f0940c2d73')]", - "Cognitive Services Custom Vision Trainer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b')]", - "Cognitive Services Data Reader (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b59867f0-fa02-499b-be73-45a86b5b3e1c')]", - "Cognitive Services Face Recognizer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '9894cab4-e18a-44aa-828b-cb588cd6f2d7')]", - "Cognitive Services Immersive Reader User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b2de6794-95db-4659-8781-7e080d3f2b9d')]", - "Cognitive Services Language Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f07febfe-79bc-46b1-8b37-790e26e6e498')]", - "Cognitive Services Language Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7628b7b8-a8b2-4cdc-b46f-e9b35248918e')]", - "Cognitive Services Language Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8')]", - "Cognitive Services LUIS Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f72c8140-2111-481c-87ff-72b910f6e3f8')]", - "Cognitive Services LUIS Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18e81cdc-4e98-4e29-a639-e7d10c5a6226')]", - "Cognitive Services LUIS Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6322a993-d5c9-4bed-b113-e49bbea25b27')]", - "Cognitive Services Metrics Advisor Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cb43c632-a144-4ec5-977c-e80c4affc34a')]", - "Cognitive Services Metrics Advisor User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3b20f47b-3825-43cb-8114-4bd2201156a8')]", - "Cognitive Services OpenAI Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a001fd3d-188f-4b5d-821b-7da978bf7442')]", - "Cognitive Services OpenAI User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "Cognitive Services QnA Maker Editor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f4cc2bf9-21be-47a1-bdf1-5c5804381025')]", - "Cognitive Services QnA Maker Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '466ccd10-b268-4a11-b098-b4849f024126')]", - "Cognitive Services Speech Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0e75ca1e-0464-4b4d-8b93-68208a576181')]", - "Cognitive Services Speech User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f2dc8367-1007-4938-bd23-fe263f013447')]", - "Cognitive Services User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a97b65f3-24c7-4388-baec-2e87135dc908')]", - "Azure AI Developer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - }, - "enableReferencedModulesTelemetry": false - }, - "resources": { - "cognitiveService": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2025-04-01-preview", - "name": "[parameters('name')]" - }, - "cognitiveService_deployments": { - "copy": { - "name": "cognitiveService_deployments", - "count": "[length(coalesce(parameters('deployments'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.CognitiveServices/accounts/deployments", - "apiVersion": "2025-04-01-preview", - "name": "[format('{0}/{1}', parameters('name'), coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'name'), format('{0}-deployments', parameters('name'))))]", - "properties": { - "model": "[coalesce(parameters('deployments'), createArray())[copyIndex()].model]", - "raiPolicyName": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'raiPolicyName')]", - "versionUpgradeOption": "[tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'versionUpgradeOption')]" - }, - "sku": "[coalesce(tryGet(coalesce(parameters('deployments'), createArray())[copyIndex()], 'sku'), createObject('name', parameters('sku'), 'capacity', tryGet(parameters('sku'), 'capacity'), 'tier', tryGet(parameters('sku'), 'tier'), 'size', tryGet(parameters('sku'), 'size'), 'family', tryGet(parameters('sku'), 'family')))]" - }, - "cognitiveService_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.CognitiveServices/accounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - } - }, - "cognitiveService_diagnosticSettings": { - "copy": { - "name": "cognitiveService_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - } - }, - "cognitiveService_roleAssignments": { - "copy": { - "name": "cognitiveService_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.CognitiveServices/accounts', 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')]" - } - }, - "cognitiveService_privateEndpoints": { - "copy": { - "name": "cognitiveService_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.CognitiveServices/accounts', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'account')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "12389807800450456797" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "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.5.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": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "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." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.11.0', '.', '-'), 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-05-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(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": "2022-09-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.34.44.8038", - "templateHash": "13997305779829540948" - }, - "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 - } - } - }, - "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." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2024-05-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2024-05-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } - } - }, - "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-05-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "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))]" - } - } - } - } - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'accessKey1Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey1Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key1)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'accessKey2Name'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'accessKey2Name'), 'value', listKeys('cognitiveService', '2025-04-01-preview').key2)), createArray()))]" - } - }, - "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.1.42791", - "templateHash": "1200612323329026557" - } - }, - "definitions": { - "secretSetOutputType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - }, - "secretUriWithVersion": { - "type": "string", - "metadata": { - "description": "The secret URI with version of the exported secret." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for the secret to set via the secrets export feature.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-07-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetOutputType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]", - "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" - } - } - } - } - } - } - }, - "aiProject": { - "condition": "[or(not(empty(parameters('projectName'))), not(empty(parameters('azureExistingAIProjectResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('{0}-ai-project-{1}-deployment', parameters('name'), parameters('projectName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('projectName')]" - }, - "desc": { - "value": "[parameters('projectDescription')]" - }, - "aiServicesName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "azureExistingAIProjectResourceId": { - "value": "[parameters('azureExistingAIProjectResourceId')]" - } - }, - "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.1.42791", - "templateHash": "125568697111155565" - } - }, - "definitions": { - "aiProjectOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI project." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the AI project." - } - }, - "apiEndpoint": { - "type": "string", - "metadata": { - "description": "Required. API endpoint for the AI project." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Output type representing AI project information." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the AI Services project." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Required. The location of the Project resource." - } - }, - "desc": { - "type": "string", - "defaultValue": "[parameters('name')]", - "metadata": { - "description": "Optional. The description of the AI Foundry project to create. Defaults to the project name." - } - }, - "aiServicesName": { - "type": "string", - "metadata": { - "description": "Required. Name of the existing Cognitive Services resource to create the AI Foundry project in." - } - }, - "tags": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Tags to be applied to the resources." - } - }, - "azureExistingAIProjectResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Use this parameter to use an existing AI project resource ID from different resource group" - } - } - }, - "variables": { - "useExistingProject": "[not(empty(parameters('azureExistingAIProjectResourceId')))]", - "existingProjName": "[if(variables('useExistingProject'), last(split(parameters('azureExistingAIProjectResourceId'), '/')), '')]", - "existingProjEndpoint": "[if(variables('useExistingProject'), format('https://{0}.services.ai.azure.com/api/projects/{1}', parameters('aiServicesName'), variables('existingProjName')), '')]" - }, - "resources": { - "cogServiceReference": { - "existing": true, - "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2024-10-01", - "name": "[parameters('aiServicesName')]" - }, - "aiProject": { - "condition": "[not(variables('useExistingProject'))]", - "type": "Microsoft.CognitiveServices/accounts/projects", - "apiVersion": "2025-04-01-preview", - "name": "[format('{0}/{1}', parameters('aiServicesName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "description": "[parameters('desc')]", - "displayName": "[parameters('name')]" - } - } - }, - "outputs": { - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "metadata": { - "description": "AI Project metadata including name, resource ID, and API endpoint." - }, - "value": { - "name": "[if(variables('useExistingProject'), variables('existingProjName'), parameters('name'))]", - "resourceId": "[if(variables('useExistingProject'), parameters('azureExistingAIProjectResourceId'), resourceId('Microsoft.CognitiveServices/accounts/projects', parameters('aiServicesName'), parameters('name')))]", - "apiEndpoint": "[if(variables('useExistingProject'), variables('existingProjEndpoint'), reference('aiProject').endpoints['AI Foundry API'])]" - } - } - } - } - } - } - }, - "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[reference('aiProject').outputs.aiProjectInfo.value]" - } - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[8], parameters('name'))]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingCognitiveServiceDetails')[2], variables('existingCognitiveServiceDetails')[4]), 'Microsoft.CognitiveServices/accounts', variables('existingCognitiveServiceDetails')[8]), resourceId('Microsoft.CognitiveServices/accounts', parameters('name')))]" - }, - "subscriptionId": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[2], subscription().subscriptionId)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the cognitive services account was deployed into." - }, - "value": "[if(variables('useExistingService'), variables('existingCognitiveServiceDetails')[4], resourceGroup().name)]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The service endpoint of the cognitive services account." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoint, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')).properties.endpoint)]" - }, - "endpoints": { - "$ref": "#/definitions/endpointType", - "metadata": { - "description": "All endpoints available for the cognitive services account, types depends on the cognitive service kind." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting').endpoints, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')).properties.endpoints)]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full').identity.principalId, tryGet(tryGet(if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')), 'identity'), 'principalId'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full').location, if(variables('useExistingService'), reference('cognitiveServiceExisting', '2025-04-01-preview', 'full'), reference('cognitiveServiceNew', '2025-04-01-preview', 'full')).location)]" - }, - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognigive_service_dependencies').outputs.exportedSecrets.value, reference('cognigive_service_dependencies').outputs.exportedSecrets.value)]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the congitive services account." - }, - "value": "[if(variables('useExistingService'), reference('existing_cognigive_service_dependencies').outputs.privateEndpoints.value, reference('cognigive_service_dependencies').outputs.privateEndpoints.value)]" - }, - "aiProjectInfo": { - "$ref": "#/definitions/aiProjectOutputType", - "value": "[if(variables('useExistingService'), reference('existing_cognigive_service_dependencies').outputs.aiProjectInfo.value, reference('cognigive_service_dependencies').outputs.aiProjectInfo.value)]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "cogServiceRoleAssignmentsNew": { - "condition": "[not(variables('useExistingResourceId'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('cogServiceRoleAssignmentsNew-{0}', uniqueString('cogServiceRoleAssignmentsNew', deployment().name))]", - "subscriptionId": "[subscription().subscriptionId]", - "resourceGroup": "[resourceGroup().name]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('new-{0}', guid(take(format('avm.res.app.container-app.{0}', variables('containerAppResourceName')), 64), reference('aiFoundryAiServices').outputs.resourceId.value))]" - }, - "principalId": { - "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" - }, - "aiServiceName": { - "value": "[reference('aiFoundryAiServices').outputs.name.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "12310021365875387766" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the role assignment resource. Typically generated using `guid()` for uniqueness." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The object ID of the principal (user, group, or service principal) to whom the role will be assigned." - } - }, - "aiServiceName": { - "type": "string", - "metadata": { - "description": "The name of the existing Azure Cognitive Services account." - } - }, - "principalType": { - "type": "string", - "defaultValue": "ServicePrincipal", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ] - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiDeveloperAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'cognitiveServiceOpenAIUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - } - ] - } - }, - "dependsOn": [ - "aiFoundryAiServices", - "containerApp" - ] - }, - "cogServiceRoleAssignmentsExisting": { - "condition": "[variables('useExistingResourceId')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('cogServiceRoleAssignmentsExisting-{0}', uniqueString('cogServiceRoleAssignmentsExisting', deployment().name))]", - "subscriptionId": "[split(parameters('existingFoundryProjectResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('existingFoundryProjectResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('reuse-{0}', guid(take(format('avm.res.app.container-app.{0}', variables('containerAppResourceName')), 64), reference('aiFoundryAiServices').outputs.aiProjectInfo.value.resourceId))]" - }, - "principalId": { - "value": "[tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')]" - }, - "aiServiceName": { - "value": "[reference('aiFoundryAiServices').outputs.name.value]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "12310021365875387766" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the role assignment resource. Typically generated using `guid()` for uniqueness." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The object ID of the principal (user, group, or service principal) to whom the role will be assigned." - } - }, - "aiServiceName": { - "type": "string", - "metadata": { - "description": "The name of the existing Azure Cognitive Services account." - } - }, - "principalType": { - "type": "string", - "defaultValue": "ServicePrincipal", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ] - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiDeveloperAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'cognitiveServiceOpenAIUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - } - ] - } - }, - "dependsOn": [ - "aiFoundryAiServices", - "containerApp" - ] - }, - "userOpenAiRoleAssignment": { - "condition": "[and(variables('aiFoundryAIservicesEnabled'), not(variables('useExistingResourceId')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('user-openai-{0}', uniqueString(variables('deployingUserPrincipalId'), variables('aiFoundryAiServicesResourceName'))), 64)]", - "subscriptionId": "[subscription().subscriptionId]", - "resourceGroup": "[resourceGroup().name]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('user-openai-{0}', uniqueString(variables('deployingUserPrincipalId'), variables('aiFoundryAiServicesResourceName')))]" - }, - "principalId": { - "value": "[variables('deployingUserPrincipalId')]" - }, - "aiServiceName": { - "value": "[reference('aiFoundryAiServices').outputs.name.value]" - }, - "principalType": { - "value": "User" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "12310021365875387766" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the role assignment resource. Typically generated using `guid()` for uniqueness." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The object ID of the principal (user, group, or service principal) to whom the role will be assigned." - } - }, - "aiServiceName": { - "type": "string", - "metadata": { - "description": "The name of the existing Azure Cognitive Services account." - } - }, - "principalType": { - "type": "string", - "defaultValue": "ServicePrincipal", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ] - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiDeveloperAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'cognitiveServiceOpenAIUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - } - ] - } - }, - "dependsOn": [ - "aiFoundryAiServices" - ] - }, - "userOpenAiRoleAssignmentExisting": { - "condition": "[and(variables('aiFoundryAIservicesEnabled'), variables('useExistingResourceId'))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('user-openai-existing-{0}', uniqueString(variables('deployingUserPrincipalId'), variables('aiFoundryAiServicesResourceName'))), 64)]", - "subscriptionId": "[split(parameters('existingFoundryProjectResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('existingFoundryProjectResourceId'), '/')[4]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('user-openai-existing-{0}', uniqueString(variables('deployingUserPrincipalId'), variables('aiFoundryAiServicesResourceName')))]" - }, - "principalId": { - "value": "[variables('deployingUserPrincipalId')]" - }, - "aiServiceName": { - "value": "[reference('aiFoundryAiServices').outputs.name.value]" - }, - "principalType": { - "value": "User" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "12310021365875387766" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the role assignment resource. Typically generated using `guid()` for uniqueness." - } - }, - "principalId": { - "type": "string", - "metadata": { - "description": "The object ID of the principal (user, group, or service principal) to whom the role will be assigned." - } - }, - "aiServiceName": { - "type": "string", - "metadata": { - "description": "The name of the existing Azure Cognitive Services account." - } - }, - "principalType": { - "type": "string", - "defaultValue": "ServicePrincipal", - "allowedValues": [ - "Device", - "ForeignGroup", - "Group", - "ServicePrincipal", - "User" - ] - } - }, - "resources": [ - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'aiDeveloperAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', parameters('aiServiceName'))]", - "name": "[guid(parameters('name'), 'cognitiveServiceOpenAIUserAccessFoundry')]", - "properties": { - "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd')]", - "principalId": "[parameters('principalId')]", - "principalType": "[parameters('principalType')]" - } - } - ] - } - }, - "dependsOn": [ - "aiFoundryAiServices" - ] - }, - "privateDnsZonesCosmosDb": { - "condition": "[variables('virtualNetworkEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.network.private-dns-zone.cosmos-db.{0}', parameters('solutionPrefix')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "privatelink.documents.azure.com" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "virtualNetworkLinks": { - "value": [ - { - "name": "vnetlink-cosmosdb", - "virtualNetworkResourceId": "[reference('virtualNetwork').outputs.resourceId.value]" - } - ] - }, - "tags": { - "value": "[parameters('tags')]" - } - }, - "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.32.4.45862", - "templateHash": "83178825086050429" - }, - "name": "Private DNS Zones", - "description": "This module deploys a Private DNS zone.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "nullable": true - }, - "aType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipv4Address": { - "type": "string", - "metadata": { - "description": "Required. The IPv4 address of this A record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of A records in the record set." - } - } - } - }, - "nullable": true - }, - "aaaaType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "aaaaRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ipv6Address": { - "type": "string", - "metadata": { - "description": "Required. The IPv6 address of this AAAA record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of AAAA records in the record set." - } - } - } - }, - "nullable": true - }, - "cnameType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "cnameRecord": { - "type": "object", - "properties": { - "cname": { - "type": "string", - "metadata": { - "description": "Required. The canonical name of the CNAME record." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The CNAME record in the record set." - } - } - } - }, - "nullable": true - }, - "mxType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "mxRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "exchange": { - "type": "string", - "metadata": { - "description": "Required. The domain name of the mail host for this MX record." - } - }, - "preference": { - "type": "int", - "metadata": { - "description": "Required. The preference value for this MX record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of MX records in the record set." - } - } - } - }, - "nullable": true - }, - "ptrType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "ptrRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "ptrdname": { - "type": "string", - "metadata": { - "description": "Required. The PTR target domain name for this PTR record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of PTR records in the record set." - } - } - } - }, - "nullable": true - }, - "soaType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "soaRecord": { - "type": "object", - "properties": { - "email": { - "type": "string", - "metadata": { - "description": "Required. The email contact for this SOA record." - } - }, - "expireTime": { - "type": "int", - "metadata": { - "description": "Required. The expire time for this SOA record." - } - }, - "host": { - "type": "string", - "metadata": { - "description": "Required. The domain name of the authoritative name server for this SOA record." - } - }, - "minimumTtl": { - "type": "int", - "metadata": { - "description": "Required. The minimum value for this SOA record. By convention this is used to determine the negative caching duration." - } - }, - "refreshTime": { - "type": "int", - "metadata": { - "description": "Required. The refresh value for this SOA record." - } - }, - "retryTime": { - "type": "int", - "metadata": { - "description": "Required. The retry time for this SOA record." - } - }, - "serialNumber": { - "type": "int", - "metadata": { - "description": "Required. The serial number for this SOA record." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The SOA record in the record set." - } - } - } - }, - "nullable": true - }, - "srvType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "srvRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "priority": { - "type": "int", - "metadata": { - "description": "Required. The priority value for this SRV record." - } - }, - "weight": { - "type": "int", - "metadata": { - "description": "Required. The weight value for this SRV record." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. The port value for this SRV record." - } - }, - "target": { - "type": "string", - "metadata": { - "description": "Required. The target domain name for this SRV record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of SRV records in the record set." - } - } - } - }, - "nullable": true - }, - "txtType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata of the record." - } - }, - "ttl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The TTL of the record." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "txtRecords": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The text value of this TXT record." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of TXT records in the record set." - } - } - } - }, - "nullable": true - }, - "virtualNetworkLinkType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "minLength": 1, - "maxLength": 80, - "metadata": { - "description": "Optional. The resource name." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the virtual network to link." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Region where the resource lives." - } - }, - "registrationEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Resource tags." - } - }, - "resolutionPolicy": { - "type": "string", - "allowedValues": [ - "Default", - "NxDomainRedirect" - ], - "nullable": true, - "metadata": { - "description": "Optional. The resolution type of the private-dns-zone fallback machanism." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Private DNS zone name." - } - }, - "a": { - "$ref": "#/definitions/aType", - "metadata": { - "description": "Optional. Array of A records." - } - }, - "aaaa": { - "$ref": "#/definitions/aaaaType", - "metadata": { - "description": "Optional. Array of AAAA records." - } - }, - "cname": { - "$ref": "#/definitions/cnameType", - "metadata": { - "description": "Optional. Array of CNAME records." - } - }, - "mx": { - "$ref": "#/definitions/mxType", - "metadata": { - "description": "Optional. Array of MX records." - } - }, - "ptr": { - "$ref": "#/definitions/ptrType", - "metadata": { - "description": "Optional. Array of PTR records." - } - }, - "soa": { - "$ref": "#/definitions/soaType", - "metadata": { - "description": "Optional. Array of SOA records." - } - }, - "srv": { - "$ref": "#/definitions/srvType", - "metadata": { - "description": "Optional. Array of SRV records." - } - }, - "txt": { - "$ref": "#/definitions/txtType", - "metadata": { - "description": "Optional. Array of TXT records." - } - }, - "virtualNetworkLinks": { - "$ref": "#/definitions/virtualNetworkLinkType", - "metadata": { - "description": "Optional. Array of custom objects describing vNet links of the DNS zone. Each object should contain properties 'virtualNetworkResourceId' and 'registrationEnabled'. The 'vnetResourceId' is a resource ID of a vNet to link, 'registrationEnabled' (bool) enables automatic DNS registration in the zone for the linked vNet." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "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')]", - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privatednszone.{0}.{1}', replace('0.7.0', '.', '-'), 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" - } - } - } - } - }, - "privateDnsZone": { - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]" - }, - "privateDnsZone_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/privateDnsZones/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_roleAssignments": { - "copy": { - "name": "privateDnsZone_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones', 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": [ - "privateDnsZone" - ] - }, - "privateDnsZone_A": { - "copy": { - "name": "privateDnsZone_A", - "count": "[length(coalesce(parameters('a'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-ARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('a'), createArray())[copyIndex()].name]" - }, - "aRecords": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'aRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('a'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "2531120132215940282" - }, - "name": "Private DNS Zone A record", - "description": "This module deploys a Private DNS Zone A record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the A record." - } - }, - "aRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of A records in the record set." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "A": { - "type": "Microsoft.Network/privateDnsZones/A", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aRecords": "[parameters('aRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "A_roleAssignments": { - "copy": { - "name": "A_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/A/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), 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": [ - "A" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed A record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed A record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/A', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed A record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_AAAA": { - "copy": { - "name": "privateDnsZone_AAAA", - "count": "[length(coalesce(parameters('aaaa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-AAAARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('aaaa'), createArray())[copyIndex()].name]" - }, - "aaaaRecords": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'aaaaRecords')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('aaaa'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "16709340450244912125" - }, - "name": "Private DNS Zone AAAA record", - "description": "This module deploys a Private DNS Zone AAAA record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the AAAA record." - } - }, - "aaaaRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of AAAA records in the record set." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "AAAA": { - "type": "Microsoft.Network/privateDnsZones/AAAA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "aaaaRecords": "[parameters('aaaaRecords')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "AAAA_roleAssignments": { - "copy": { - "name": "AAAA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/AAAA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), 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": [ - "AAAA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed AAAA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed AAAA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/AAAA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed AAAA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_CNAME": { - "copy": { - "name": "privateDnsZone_CNAME", - "count": "[length(coalesce(parameters('cname'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-CNAMERecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('cname'), createArray())[copyIndex()].name]" - }, - "cnameRecord": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'cnameRecord')]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'metadata')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('cname'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "9976020649752073181" - }, - "name": "Private DNS Zone CNAME record", - "description": "This module deploys a Private DNS Zone CNAME record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the CNAME record." - } - }, - "cnameRecord": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A CNAME record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "CNAME": { - "type": "Microsoft.Network/privateDnsZones/CNAME", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "cnameRecord": "[parameters('cnameRecord')]", - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]" - } - }, - "CNAME_roleAssignments": { - "copy": { - "name": "CNAME_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/CNAME/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), 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": [ - "CNAME" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed CNAME record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed CNAME record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/CNAME', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed CNAME record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_MX": { - "copy": { - "name": "privateDnsZone_MX", - "count": "[length(coalesce(parameters('mx'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-MXRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('mx'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'metadata')]" - }, - "mxRecords": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'mxRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('mx'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "2520323624213076361" - }, - "name": "Private DNS Zone MX record", - "description": "This module deploys a Private DNS Zone MX record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the MX record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "mxRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of MX records in the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "MX": { - "type": "Microsoft.Network/privateDnsZones/MX", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "mxRecords": "[parameters('mxRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "MX_roleAssignments": { - "copy": { - "name": "MX_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/MX/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), 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": [ - "MX" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed MX record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed MX record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/MX', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed MX record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_PTR": { - "copy": { - "name": "privateDnsZone_PTR", - "count": "[length(coalesce(parameters('ptr'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-PTRRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('ptr'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'metadata')]" - }, - "ptrRecords": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ptrRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('ptr'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "3080404733048745471" - }, - "name": "Private DNS Zone PTR record", - "description": "This module deploys a Private DNS Zone PTR record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the PTR record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ptrRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of PTR records in the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "PTR": { - "type": "Microsoft.Network/privateDnsZones/PTR", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ptrRecords": "[parameters('ptrRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "PTR_roleAssignments": { - "copy": { - "name": "PTR_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/PTR/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), 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": [ - "PTR" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed PTR record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed PTR record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/PTR', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed PTR record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SOA": { - "copy": { - "name": "privateDnsZone_SOA", - "count": "[length(coalesce(parameters('soa'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-SOARecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('soa'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'metadata')]" - }, - "soaRecord": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'soaRecord')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('soa'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "6653951445614700931" - }, - "name": "Private DNS Zone SOA record", - "description": "This module deploys a Private DNS Zone SOA record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SOA record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "soaRecord": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. A SOA record." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SOA": { - "type": "Microsoft.Network/privateDnsZones/SOA", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "soaRecord": "[parameters('soaRecord')]", - "ttl": "[parameters('ttl')]" - } - }, - "SOA_roleAssignments": { - "copy": { - "name": "SOA_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SOA/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), 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": [ - "SOA" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SOA record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SOA record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SOA', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SOA record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_SRV": { - "copy": { - "name": "privateDnsZone_SRV", - "count": "[length(coalesce(parameters('srv'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-SRVRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('srv'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'metadata')]" - }, - "srvRecords": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'srvRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('srv'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "5790774778713328446" - }, - "name": "Private DNS Zone SRV record", - "description": "This module deploys a Private DNS Zone SRV record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the SRV record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "srvRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of SRV records in the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "SRV": { - "type": "Microsoft.Network/privateDnsZones/SRV", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "srvRecords": "[parameters('srvRecords')]", - "ttl": "[parameters('ttl')]" - } - }, - "SRV_roleAssignments": { - "copy": { - "name": "SRV_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/SRV/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), 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": [ - "SRV" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed SRV record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed SRV record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/SRV', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed SRV record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_TXT": { - "copy": { - "name": "privateDnsZone_TXT", - "count": "[length(coalesce(parameters('txt'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-TXTRecord-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('txt'), createArray())[copyIndex()].name]" - }, - "metadata": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'metadata')]" - }, - "txtRecords": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'txtRecords')]" - }, - "ttl": { - "value": "[coalesce(tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'ttl'), 3600)]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('txt'), createArray())[copyIndex()], 'roleAssignments')]" - } - }, - "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.32.4.45862", - "templateHash": "1855369119498044639" - }, - "name": "Private DNS Zone TXT record", - "description": "This module deploys a Private DNS Zone TXT record.", - "owner": "Azure/module-maintainers" - }, - "definitions": { - "roleAssignmentType": { - "type": "array", - "items": { - "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." - } - } - } - }, - "nullable": true - } - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the TXT record." - } - }, - "metadata": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The metadata attached to the record set." - } - }, - "ttl": { - "type": "int", - "defaultValue": 3600, - "metadata": { - "description": "Optional. The TTL (time-to-live) of the records in the record set." - } - }, - "txtRecords": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The list of TXT records in the record set." - } - }, - "roleAssignments": { - "$ref": "#/definitions/roleAssignmentType", - "metadata": { - "description": "Optional. Array of role assignments to create." - } - } - }, - "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')]", - "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", - "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "TXT": { - "type": "Microsoft.Network/privateDnsZones/TXT", - "apiVersion": "2020-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "properties": { - "metadata": "[parameters('metadata')]", - "ttl": "[parameters('ttl')]", - "txtRecords": "[parameters('txtRecords')]" - } - }, - "TXT_roleAssignments": { - "copy": { - "name": "TXT_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Network/privateDnsZones/{0}/TXT/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), 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": [ - "TXT" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed TXT record." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed TXT record." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/TXT', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed TXT record." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - }, - "privateDnsZone_virtualNetworkLinks": { - "copy": { - "name": "privateDnsZone_virtualNetworkLinks", - "count": "[length(coalesce(parameters('virtualNetworkLinks'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-PrivateDnsZone-VirtualNetworkLink-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "privateDnsZoneName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'name'), format('{0}-vnetlink', last(split(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId, '/'))))]" - }, - "virtualNetworkResourceId": { - "value": "[coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()].virtualNetworkResourceId]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'location'), 'global')]" - }, - "registrationEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'registrationEnabled'), false())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "resolutionPolicy": { - "value": "[tryGet(coalesce(parameters('virtualNetworkLinks'), createArray())[copyIndex()], 'resolutionPolicy')]" - } - }, - "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.32.4.45862", - "templateHash": "15326596012552051215" - }, - "name": "Private DNS Zone Virtual Network Link", - "description": "This module deploys a Private DNS Zone Virtual Network Link.", - "owner": "Azure/module-maintainers" - }, - "parameters": { - "privateDnsZoneName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Private DNS zone. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "defaultValue": "[format('{0}-vnetlink', last(split(parameters('virtualNetworkResourceId'), '/')))]", - "metadata": { - "description": "Optional. The name of the virtual network link." - } - }, - "location": { - "type": "string", - "defaultValue": "global", - "metadata": { - "description": "Optional. The location of the PrivateDNSZone. Should be global." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registrationEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Is auto-registration of virtual machine records in the virtual network in the Private DNS zone enabled?." - } - }, - "virtualNetworkResourceId": { - "type": "string", - "metadata": { - "description": "Required. Link to another virtual network resource ID." - } - }, - "resolutionPolicy": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resolution policy on the virtual network link. Only applicable for virtual network links to privatelink zones, and for A,AAAA,CNAME queries. When set to `NxDomainRedirect`, Azure DNS resolver falls back to public resolution if private dns query resolution results in non-existent domain response. `Default` is configured as the default option." - } - } - }, - "resources": { - "privateDnsZone": { - "existing": true, - "type": "Microsoft.Network/privateDnsZones", - "apiVersion": "2020-06-01", - "name": "[parameters('privateDnsZoneName')]" - }, - "virtualNetworkLink": { - "type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks", - "apiVersion": "2024-06-01", - "name": "[format('{0}/{1}', parameters('privateDnsZoneName'), parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "registrationEnabled": "[parameters('registrationEnabled')]", - "virtualNetwork": { - "id": "[parameters('virtualNetworkResourceId')]" - }, - "resolutionPolicy": "[parameters('resolutionPolicy')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the deployed virtual network link." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the deployed virtual network link." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones/virtualNetworkLinks', parameters('privateDnsZoneName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group of the deployed virtual network link." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('virtualNetworkLink', '2024-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "privateDnsZone" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private DNS zone was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private DNS zone." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private DNS zone." - }, - "value": "[resourceId('Microsoft.Network/privateDnsZones', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateDnsZone', '2020-06-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "virtualNetwork" - ] - }, - "cosmosDb": { - "condition": "[variables('cosmosDbAccountEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.document-db.database-account.{0}', variables('cosmosDbResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'name'), format('cosmos-{0}', parameters('solutionPrefix')))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'tags'), parameters('tags'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "databaseAccountOfferType": { - "value": "Standard" - }, - "enableFreeTier": { - "value": false - }, - "networkRestrictions": { - "value": { - "networkAclBypass": "None", - "publicNetworkAccess": "[if(variables('virtualNetworkEnabled'), 'Disabled', 'Enabled')]" - } - }, - "privateEndpoints": "[if(variables('virtualNetworkEnabled'), createObject('value', createArray(createObject('name', format('pep-{0}', variables('cosmosDbResourceName')), 'customNetworkInterfaceName', format('nic-{0}', variables('cosmosDbResourceName')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', reference('privateDnsZonesCosmosDb').outputs.resourceId.value))), 'service', 'Sql', 'subnetResourceId', coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'subnetResourceId'), reference('virtualNetwork').outputs.subnetResourceIds.value[0])))), createObject('value', createArray()))]", - "sqlDatabases": { - "value": "[concat(coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'sqlDatabases'), createArray()), createArray(createObject('name', variables('cosmosDbDatabaseName'), 'containers', createArray(createObject('name', variables('cosmosDbDatabaseMemoryContainerName'), 'paths', createArray('/session_id'), 'kind', 'Hash', 'version', 2)))))]" - }, - "locations": { - "value": [ - { - "locationName": "[coalesce(tryGet(parameters('cosmosDbAccountConfiguration'), 'location'), parameters('solutionLocation'))]", - "failoverPriority": 0, - "isZoneRedundant": false - } - ] - }, - "capabilitiesToAdd": { - "value": [ - "EnableServerless" - ] - }, - "sqlRoleAssignmentsPrincipalIds": { - "value": "[concat(createArray(tryGet(tryGet(reference('containerApp').outputs, 'systemAssignedMIPrincipalId'), 'value')), createArray(variables('deployingUserPrincipalId')))]" - }, - "sqlRoleDefinitions": { - "value": [ - { - "roleType": "CustomRole", - "roleName": "Cosmos DB SQL Data Contributor", - "name": "cosmos-db-sql-data-contributor", - "dataAction": [ - "Microsoft.DocumentDB/databaseAccounts/readMetadata", - "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*", - "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*" - ] - } - ] - } - }, - "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.34.44.8038", - "templateHash": "4234855794516527664" - }, - "name": "DocumentDB Database Accounts", - "description": "This module deploys a DocumentDB Database Account." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the private endpoint output." - } - }, - "failoverLocationType": { - "type": "object", - "properties": { - "failoverPriority": { - "type": "int", - "metadata": { - "description": "Required. The failover priority of the region. A failover priority of 0 indicates a write region. The maximum value for a failover priority = (total number of regions - 1). Failover priority values must be unique for each of the regions in which the database account exists." - } - }, - "isZoneRedundant": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Default to true. Flag to indicate whether or not this region is an AvailabilityZone region." - } - }, - "locationName": { - "type": "string", - "metadata": { - "description": "Required. The name of the region." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the failover location." - } - }, - "sqlRoleDefinitionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL Role Definition." - } - }, - "dataAction": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. An array of data actions that are allowed." - } - }, - "roleName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A user-friendly name for the Role Definition. Must be unique for the database account." - } - }, - "roleType": { - "type": "string", - "allowedValues": [ - "BuiltInRole", - "CustomRole" - ], - "nullable": true, - "metadata": { - "description": "Optional. Indicates whether the Role Definition was built-in or user created." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SQL Role Definitions." - } - }, - "sqlDatabaseType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "containers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "analyticalStorageTtl": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "properties": { - "conflictResolutionPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The conflict resolution path in the case of LastWriterWins mode. Required if `mode` is set to 'LastWriterWins'." - } - }, - "conflictResolutionProcedure": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The procedure to resolve conflicts in the case of custom mode. Required if `mode` is set to 'Custom'." - } - }, - "mode": { - "type": "string", - "allowedValues": [ - "Custom", - "LastWriterWins" - ], - "metadata": { - "description": "Required. Indicates the conflict resolution mode." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - } - }, - "defaultTtl": { - "type": "int", - "nullable": true, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "indexingPolicy": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Indexing policy of the container." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "allowedValues": [ - 1, - 2 - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used." - } - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "items": { - "type": "object", - "properties": { - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. List of paths must be unique for each document in the Azure Cosmos DB service." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the SQL database." - } - }, - "secretsExportConfigurationType": { - "type": "object", - "properties": { - "keyVaultResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the key vault where to store the secrets of this module." - } - }, - "primaryWriteKeySecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary write key secret name to create." - } - }, - "primaryReadOnlyKeySecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary readonly key secret name to create." - } - }, - "primaryWriteConnectionStringSecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary write connection string secret name to create." - } - }, - "primaryReadonlyConnectionStringSecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary readonly connection string secret name to create." - } - }, - "secondaryWriteKeySecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary write key secret name to create." - } - }, - "secondaryReadonlyKeySecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary readonly key secret name to create." - } - }, - "secondaryWriteConnectionStringSecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary write connection string secret name to create." - } - }, - "secondaryReadonlyConnectionStringSecretName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The primary readonly connection string secret name to create." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the secrets export configuration." - } - }, - "secretsOutputType": { - "type": "object", - "properties": {}, - "additionalProperties": { - "$ref": "#/definitions/secretSetType", - "metadata": { - "description": "An exported secret's references." - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the secrets output." - } - }, - "networkRestrictionType": { - "type": "object", - "properties": { - "ipRules": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. A single IPv4 address or a single IPv4 address range in CIDR format. Provided IPs must be well-formatted and cannot be contained in one of the following ranges: 10.0.0.0/8, 100.64.0.0/10, 172.16.0.0/12, 192.168.0.0/16, since these are not enforceable by the IP address filter. Example of valid inputs: \"23.40.210.245\" or \"23.40.210.0/8\"." - } - }, - "networkAclBypass": { - "type": "string", - "allowedValues": [ - "AzureServices", - "None" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to None. Specifies the network ACL bypass for Azure services." - } - }, - "publicNetworkAccess": { - "type": "string", - "allowedValues": [ - "Disabled", - "Enabled" - ], - "nullable": true, - "metadata": { - "description": "Optional. Default to Disabled. Whether requests from Public Network are allowed." - } - }, - "virtualNetworkRules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of a subnet." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. List of Virtual Network ACL rules configured for the Cosmos DB account.." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the network restriction." - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "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": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointMultiServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the private endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "metadata": { - "description": "Required. The subresource to deploy the private endpoint for. For example \"blob\", \"table\", \"queue\" or \"file\" for a Storage Account's Private Endpoints." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can NOT be assumed (i.e., for services that have more than one subresource, like Storage Account with Blob (blob, table, queue, file, ...).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - }, - "secretSetType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - } - }, - "metadata": { - "description": "The type for the secret set.", - "__bicep_imported_from!": { - "sourceTemplate": "modules/keyVaultExport.bicep" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Database Account." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Default to current resource group scope location. Location for all resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the Database Account resource." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "databaseAccountOfferType": { - "type": "string", - "defaultValue": "Standard", - "allowedValues": [ - "Standard" - ], - "metadata": { - "description": "Optional. Default to Standard. The offer type for the Azure Cosmos DB database account." - } - }, - "locations": { - "type": "array", - "items": { - "$ref": "#/definitions/failoverLocationType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Default to the location where the account is deployed. Locations enabled for the Cosmos DB account." - } - }, - "defaultConsistencyLevel": { - "type": "string", - "defaultValue": "Session", - "allowedValues": [ - "Eventual", - "ConsistentPrefix", - "Session", - "BoundedStaleness", - "Strong" - ], - "metadata": { - "description": "Optional. Default to Session. The default consistency level of the Cosmos DB account." - } - }, - "disableLocalAuth": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Default to true. Opt-out of local authentication and ensure only MSI and AAD can be used exclusively for authentication." - } - }, - "enableAnalyticalStorage": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Default to false. Flag to indicate whether to enable storage analytics." - } - }, - "automaticFailover": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Default to true. Enable automatic failover for regions." - } - }, - "enableFreeTier": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Default to false. Flag to indicate whether Free Tier is enabled." - } - }, - "enableMultipleWriteLocations": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Default to false. Enables the account to write in multiple locations. Periodic backup must be used if enabled." - } - }, - "disableKeyBasedMetadataWriteAccess": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Default to true. Disable write operations on metadata resources (databases, containers, throughput) via account keys." - } - }, - "maxStalenessPrefix": { - "type": "int", - "defaultValue": 100000, - "minValue": 1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to 100000. Max stale requests. Required for BoundedStaleness. Valid ranges, Single Region: 10 to 1000000. Multi Region: 100000 to 1000000." - } - }, - "maxIntervalInSeconds": { - "type": "int", - "defaultValue": 300, - "minValue": 5, - "maxValue": 86400, - "metadata": { - "description": "Optional. Default to 300. Max lag time (minutes). Required for BoundedStaleness. Valid ranges, Single Region: 5 to 84600. Multi Region: 300 to 86400." - } - }, - "serverVersion": { - "type": "string", - "defaultValue": "4.2", - "allowedValues": [ - "3.2", - "3.6", - "4.0", - "4.2", - "5.0", - "6.0", - "7.0" - ], - "metadata": { - "description": "Optional. Default to 4.2. Specifies the MongoDB server version to use." - } - }, - "sqlDatabases": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlDatabaseType" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. SQL Databases configurations." - } - }, - "sqlRoleAssignmentsPrincipalIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. SQL Role Definitions configurations." - } - }, - "sqlRoleDefinitions": { - "type": "array", - "items": { - "$ref": "#/definitions/sqlRoleDefinitionType" - }, - "nullable": true, - "metadata": { - "description": "Optional. SQL Role Definitions configurations." - } - }, - "mongodbDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. MongoDB Databases configurations." - } - }, - "gremlinDatabases": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Gremlin Databases configurations." - } - }, - "tables": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Table configurations." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "totalThroughputLimit": { - "type": "int", - "defaultValue": -1, - "metadata": { - "description": "Optional. Default to unlimited. The total throughput limit imposed on this Cosmos DB account (RU/s)." - } - }, - "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." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "capabilitiesToAdd": { - "type": "array", - "items": { - "type": "string" - }, - "defaultValue": [], - "allowedValues": [ - "EnableCassandra", - "EnableTable", - "EnableGremlin", - "EnableMongo", - "DisableRateLimitingResponses", - "EnableServerless", - "EnableNoSQLVectorSearch", - "EnableNoSQLFullTextSearch", - "EnableMaterializedViews", - "DeleteAllItemsByPartitionKey" - ], - "metadata": { - "description": "Optional. List of Cosmos DB capabilities for the account. THE DeleteAllItemsByPartitionKey VALUE USED IN THIS PARAMETER IS USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE PRODUCT DOCS FOR CLARIFICATION." - } - }, - "backupPolicyType": { - "type": "string", - "defaultValue": "Continuous", - "allowedValues": [ - "Periodic", - "Continuous" - ], - "metadata": { - "description": "Optional. Default to Continuous. Describes the mode of backups. Periodic backup must be used if multiple write locations are used." - } - }, - "backupPolicyContinuousTier": { - "type": "string", - "defaultValue": "Continuous30Days", - "allowedValues": [ - "Continuous30Days", - "Continuous7Days" - ], - "metadata": { - "description": "Optional. Default to Continuous30Days. Configuration values for continuous mode backup." - } - }, - "backupIntervalInMinutes": { - "type": "int", - "defaultValue": 240, - "minValue": 60, - "maxValue": 1440, - "metadata": { - "description": "Optional. Default to 240. An integer representing the interval in minutes between two backups. Only applies to periodic backup type." - } - }, - "backupRetentionIntervalInHours": { - "type": "int", - "defaultValue": 8, - "minValue": 2, - "maxValue": 720, - "metadata": { - "description": "Optional. Default to 8. An integer representing the time (in hours) that each backup is retained. Only applies to periodic backup type." - } - }, - "backupStorageRedundancy": { - "type": "string", - "defaultValue": "Local", - "allowedValues": [ - "Geo", - "Local", - "Zone" - ], - "metadata": { - "description": "Optional. Default to Local. Enum to indicate type of backup residency. Only applies to periodic backup type." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointMultiServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "secretsExportConfiguration": { - "$ref": "#/definitions/secretsExportConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. Key vault reference and secret settings for the module's secrets export." - } - }, - "networkRestrictions": { - "$ref": "#/definitions/networkRestrictionType", - "defaultValue": { - "ipRules": [], - "virtualNetworkRules": [], - "publicNetworkAccess": "Disabled" - }, - "metadata": { - "description": "Optional. The network configuration of this module. Defaults to `{ ipRules: [], virtualNetworkRules: [], publicNetworkAccess: 'Disabled' }`." - } - }, - "minimumTlsVersion": { - "type": "string", - "defaultValue": "Tls12", - "allowedValues": [ - "Tls12" - ], - "metadata": { - "description": "Optional. Default to TLS 1.2. Enum to indicate the minimum allowed TLS version. Azure Cosmos DB for MongoDB RU and Apache Cassandra only work with TLS 1.2 or later." - } - } - }, - "variables": { - "copy": [ - { - "name": "databaseAccount_locations", - "count": "[length(parameters('locations'))]", - "input": { - "failoverPriority": "[parameters('locations')[copyIndex('databaseAccount_locations')].failoverPriority]", - "locationName": "[parameters('locations')[copyIndex('databaseAccount_locations')].locationName]", - "isZoneRedundant": "[coalesce(tryGet(parameters('locations')[copyIndex('databaseAccount_locations')], 'isZoneRedundant'), true())]" - } - }, - { - "name": "capabilities", - "count": "[length(parameters('capabilitiesToAdd'))]", - "input": { - "name": "[parameters('capabilitiesToAdd')[copyIndex('capabilities')]]" - } - }, - { - "name": "ipRules", - "count": "[length(coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray()))]", - "input": { - "ipAddressOrRange": "[coalesce(tryGet(parameters('networkRestrictions'), 'ipRules'), createArray())[copyIndex('ipRules')]]" - } - }, - { - "name": "virtualNetworkRules", - "count": "[length(coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray()))]", - "input": { - "id": "[coalesce(tryGet(parameters('networkRestrictions'), 'virtualNetworkRules'), createArray())[copyIndex('virtualNetworkRules')].subnetResourceId]", - "ignoreMissingVnetServiceEndpoint": false - } - }, - { - "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)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "consistencyPolicy": { - "Eventual": { - "defaultConsistencyLevel": "Eventual" - }, - "ConsistentPrefix": { - "defaultConsistencyLevel": "ConsistentPrefix" - }, - "Session": { - "defaultConsistencyLevel": "Session" - }, - "BoundedStaleness": { - "defaultConsistencyLevel": "BoundedStaleness", - "maxStalenessPrefix": "[parameters('maxStalenessPrefix')]", - "maxIntervalInSeconds": "[parameters('maxIntervalInSeconds')]" - }, - "Strong": { - "defaultConsistencyLevel": "Strong" - } - }, - "defaultFailoverLocation": [ - { - "failoverPriority": 0, - "locationName": "[parameters('location')]", - "isZoneRedundant": true - } - ], - "kind": "[if(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('gremlinDatabases')))), 'GlobalDocumentDB', if(not(empty(parameters('mongodbDatabases'))), 'MongoDB', 'GlobalDocumentDB'))]", - "backupPolicy": "[if(equals(parameters('backupPolicyType'), 'Continuous'), createObject('type', parameters('backupPolicyType'), 'continuousModeProperties', createObject('tier', parameters('backupPolicyContinuousTier'))), createObject('type', parameters('backupPolicyType'), 'periodicModeProperties', createObject('backupIntervalInMinutes', parameters('backupIntervalInMinutes'), 'backupRetentionIntervalInHours', parameters('backupRetentionIntervalInHours'), 'backupStorageRedundancy', parameters('backupStorageRedundancy'))))]", - "databaseAccountProperties": "[union(createObject('databaseAccountOfferType', parameters('databaseAccountOfferType'), 'backupPolicy', variables('backupPolicy'), 'capabilities', variables('capabilities'), 'minimalTlsVersion', parameters('minimumTlsVersion'), 'capacity', createObject('totalThroughputLimit', parameters('totalThroughputLimit'))), if(or(or(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('mongodbDatabases')))), not(empty(parameters('gremlinDatabases')))), not(empty(parameters('tables')))), createObject('consistencyPolicy', variables('consistencyPolicy')[parameters('defaultConsistencyLevel')], 'enableMultipleWriteLocations', parameters('enableMultipleWriteLocations'), 'locations', if(empty(variables('databaseAccount_locations')), variables('defaultFailoverLocation'), variables('databaseAccount_locations')), 'ipRules', variables('ipRules'), 'virtualNetworkRules', variables('virtualNetworkRules'), 'networkAclBypass', coalesce(tryGet(parameters('networkRestrictions'), 'networkAclBypass'), 'None'), 'publicNetworkAccess', coalesce(tryGet(parameters('networkRestrictions'), 'publicNetworkAccess'), 'Disabled'), 'isVirtualNetworkFilterEnabled', or(not(empty(variables('ipRules'))), not(empty(variables('virtualNetworkRules')))), 'enableFreeTier', parameters('enableFreeTier'), 'enableAutomaticFailover', parameters('automaticFailover'), 'enableAnalyticalStorage', parameters('enableAnalyticalStorage')), createObject()), if(or(not(empty(parameters('sqlDatabases'))), not(empty(parameters('tables')))), createObject('disableLocalAuth', parameters('disableLocalAuth'), 'disableKeyBasedMetadataWriteAccess', parameters('disableKeyBasedMetadataWriteAccess')), createObject()), if(not(empty(parameters('mongodbDatabases'))), createObject('apiProperties', createObject('serverVersion', parameters('serverVersion'))), createObject()))]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Cosmos DB Account Reader Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fbdf93bf-df7d-467e-a4d2-9458aa1360c8')]", - "Cosmos DB Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '230815da-be43-4aae-9cb4-875f7bd000aa')]", - "CosmosBackupOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db7b14f2-5adf-42da-9f96-f2ee17bab5cb')]", - "CosmosRestoreOperator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5432c526-bc82-444a-b7ba-57c5b0b5b34f')]", - "DocumentDB Account Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5bd9cd88-fe45-4216-938b-f97437e15450')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-07-01", - "name": "[format('46d3xbcp.res.documentdb-databaseaccount.{0}.{1}', replace('0.12.0', '.', '-'), 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" - } - } - } - } - }, - "databaseAccount": { - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "kind": "[variables('kind')]", - "properties": "[variables('databaseAccountProperties')]" - }, - "databaseAccount_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.DocumentDB/databaseAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_diagnosticSettings": { - "copy": { - "name": "databaseAccount_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_roleAssignments": { - "copy": { - "name": "databaseAccount_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.DocumentDB/databaseAccounts/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', 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": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlDatabases": { - "copy": { - "name": "databaseAccount_sqlDatabases", - "count": "[length(parameters('sqlDatabases'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('location')), parameters('sqlDatabases')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('sqlDatabases')[copyIndex()].name]" - }, - "containers": { - "value": "[tryGet(parameters('sqlDatabases')[copyIndex()], 'containers')]" - }, - "throughput": { - "value": "[tryGet(parameters('sqlDatabases')[copyIndex()], 'throughput')]" - }, - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('sqlDatabases')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - } - }, - "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.34.44.8038", - "templateHash": "16080632612286518435" - }, - "name": "DocumentDB Database Account SQL Databases", - "description": "This module deploys a SQL Database in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL database ." - } - }, - "containers": { - "type": "array", - "items": { - "type": "object" - }, - "defaultValue": [], - "metadata": { - "description": "Optional. Array of containers to deploy in the SQL database." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. Setting throughput at the database level is only recommended for development/test or when workload across all containers in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the SQL database resource." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "sqlDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(equals(parameters('autoscaleSettingsMaxThroughput'), null()), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "container": { - "copy": { - "name": "container", - "count": "[length(parameters('containers'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-sqldb-{1}', uniqueString(deployment().name, parameters('name')), parameters('containers')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "sqlDatabaseName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[parameters('containers')[copyIndex()].name]" - }, - "analyticalStorageTtl": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'analyticalStorageTtl')]" - }, - "autoscaleSettingsMaxThroughput": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'autoscaleSettingsMaxThroughput')]" - }, - "conflictResolutionPolicy": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'conflictResolutionPolicy')]" - }, - "defaultTtl": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'defaultTtl')]" - }, - "indexingPolicy": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'indexingPolicy')]" - }, - "kind": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'kind')]" - }, - "version": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'version')]" - }, - "paths": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'paths')]" - }, - "throughput": "[if(and(or(not(equals(parameters('throughput'), null())), not(equals(parameters('autoscaleSettingsMaxThroughput'), null()))), equals(tryGet(parameters('containers')[copyIndex()], 'throughput'), null())), createObject('value', -1), createObject('value', tryGet(parameters('containers')[copyIndex()], 'throughput')))]", - "uniqueKeyPolicyKeys": { - "value": "[tryGet(parameters('containers')[copyIndex()], 'uniqueKeyPolicyKeys')]" - } - }, - "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.34.44.8038", - "templateHash": "8834615293032195419" - }, - "name": "DocumentDB Database Account SQL Database Containers", - "description": "This module deploys a SQL Database Container in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "sqlDatabaseName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent SQL Database. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the container." - } - }, - "analyticalStorageTtl": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Default to 0. Indicates how long data should be retained in the analytical store, for a container. Analytical store is enabled when ATTL is set with a value other than 0. If the value is set to -1, the analytical store retains all historical data, irrespective of the retention of the data in the transactional store." - } - }, - "conflictResolutionPolicy": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The conflict resolution policy for the container. Conflicts and conflict resolution policies are applicable if the Azure Cosmos DB account is configured with multiple write regions." - } - }, - "defaultTtl": { - "type": "int", - "defaultValue": -1, - "minValue": -1, - "maxValue": 2147483647, - "metadata": { - "description": "Optional. Default to -1. Default time to live (in seconds). With Time to Live or TTL, Azure Cosmos DB provides the ability to delete items automatically from a container after a certain time period. If the value is set to \"-1\", it is equal to infinity, and items don't expire by default." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Default to 400. Request Units per second. Will be ignored if autoscaleSettingsMaxThroughput is used. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "autoscaleSettingsMaxThroughput": { - "type": "int", - "nullable": true, - "maxValue": 1000000, - "metadata": { - "description": "Optional. Specifies the Autoscale settings and represents maximum throughput, the resource can scale up to. The autoscale throughput should have valid throughput values between 1000 and 1000000 inclusive in increments of 1000. If value is set to null, then autoscale will be disabled. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the container level and not at the database level." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the SQL Database resource." - } - }, - "paths": { - "type": "array", - "items": { - "type": "string" - }, - "minLength": 1, - "maxLength": 3, - "metadata": { - "description": "Required. List of paths using which data within the container can be partitioned. For kind=MultiHash it can be up to 3. For anything else it needs to be exactly 1." - } - }, - "indexingPolicy": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Indexing policy of the container." - } - }, - "uniqueKeyPolicyKeys": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. The unique key policy configuration containing a list of unique keys that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service." - } - }, - "kind": { - "type": "string", - "defaultValue": "Hash", - "allowedValues": [ - "Hash", - "MultiHash" - ], - "metadata": { - "description": "Optional. Default to Hash. Indicates the kind of algorithm used for partitioning." - } - }, - "version": { - "type": "int", - "defaultValue": 1, - "allowedValues": [ - 1, - 2 - ], - "metadata": { - "description": "Optional. Default to 1 for Hash and 2 for MultiHash - 1 is not allowed for MultiHash. Version of the partition key definition." - } - } - }, - "variables": { - "copy": [ - { - "name": "partitionKeyPaths", - "count": "[length(parameters('paths'))]", - "input": "[if(startsWith(parameters('paths')[copyIndex('partitionKeyPaths')], '/'), parameters('paths')[copyIndex('partitionKeyPaths')], format('/{0}', parameters('paths')[copyIndex('partitionKeyPaths')]))]" - } - ], - "containerResourceParams": "[union(createObject('conflictResolutionPolicy', parameters('conflictResolutionPolicy'), 'defaultTtl', parameters('defaultTtl'), 'id', parameters('name'), 'indexingPolicy', if(not(empty(parameters('indexingPolicy'))), parameters('indexingPolicy'), null()), 'partitionKey', createObject('paths', variables('partitionKeyPaths'), 'kind', parameters('kind'), 'version', if(equals(parameters('kind'), 'MultiHash'), 2, parameters('version'))), 'uniqueKeyPolicy', if(not(empty(parameters('uniqueKeyPolicyKeys'))), createObject('uniqueKeys', parameters('uniqueKeyPolicyKeys')), null())), if(not(equals(parameters('analyticalStorageTtl'), 0)), createObject('analyticalStorageTtl', parameters('analyticalStorageTtl')), createObject()))]" - }, - "resources": { - "databaseAccount::sqlDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('sqlDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "container": { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": "[variables('containerResourceParams')]", - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', if(and(equals(parameters('autoscaleSettingsMaxThroughput'), null()), not(equals(parameters('throughput'), -1))), parameters('throughput'), null()), 'autoscaleSettings', if(not(equals(parameters('autoscaleSettingsMaxThroughput'), null())), createObject('maxThroughput', parameters('autoscaleSettingsMaxThroughput')), null())))]" - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the container." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the container." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers', parameters('databaseAccountName'), parameters('sqlDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the container was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "sqlDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_sqlRoleDefinitions": { - "copy": { - "name": "databaseAccount_sqlRoleDefinitions", - "count": "[length(coalesce(parameters('sqlRoleDefinitions'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-sqlrd-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()].name]" - }, - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "dataActions": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'dataActions')]" - }, - "roleName": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'roleName')]" - }, - "roleType": { - "value": "[tryGet(coalesce(parameters('sqlRoleDefinitions'), createArray())[copyIndex()], 'roleType')]" - }, - "principalIds": { - "value": "[parameters('sqlRoleAssignmentsPrincipalIds')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "2490416937519336508" - }, - "name": "DocumentDB Database Account SQL Role.", - "description": "This module deploys SQL Role Definision and Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL Role." - } - }, - "dataActions": { - "type": "array", - "defaultValue": [ - "Microsoft.DocumentDB/databaseAccounts/readMetadata", - "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*", - "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*" - ], - "metadata": { - "description": "Optional. An array of data actions that are allowed." - } - }, - "principalIds": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Ids needs to be granted." - } - }, - "roleName": { - "type": "string", - "defaultValue": "Reader Writer", - "metadata": { - "description": "Optional. A user-friendly name for the Role Definition. Must be unique for the database account." - } - }, - "roleType": { - "type": "string", - "defaultValue": "CustomRole", - "allowedValues": [ - "CustomRole", - "BuiltInRole" - ], - "metadata": { - "description": "Optional. Indicates whether the Role Definition was built-in or user created." - } - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('sql-role-definition-{0}', uniqueString(parameters('name')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "dataActions": { - "value": "[parameters('dataActions')]" - }, - "roleName": { - "value": "[parameters('roleName')]" - }, - "roleType": { - "value": "[parameters('roleType')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16003674161646405716" - }, - "name": "DocumentDB Database Account SQL Role Definitions.", - "description": "This module deploys a SQL Role Definision in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "dataActions": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. An array of data actions that are allowed." - } - }, - "roleName": { - "type": "string", - "defaultValue": "Reader Writer", - "metadata": { - "description": "Optional. A user-friendly name for the Role Definition. Must be unique for the database account." - } - }, - "roleType": { - "type": "string", - "defaultValue": "CustomRole", - "allowedValues": [ - "CustomRole", - "BuiltInRole" - ], - "metadata": { - "description": "Optional. Indicates whether the Role Definition was built-in or user created." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), 'sql-role'))]", - "properties": { - "assignableScopes": [ - "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))]" - ], - "permissions": [ - { - "dataActions": "[parameters('dataActions')]" - } - ], - "roleName": "[parameters('roleName')]", - "type": "[parameters('roleType')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the SQL database." - }, - "value": "[guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), 'sql-role')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the SQL database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('databaseAccountName'), guid(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), parameters('databaseAccountName'), 'sql-role'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - } - }, - { - "copy": { - "name": "sqlRoleAssignment", - "count": "[length(parameters('principalIds'))]", - "mode": "serial", - "batchSize": 1 - }, - "condition": "[not(empty(parameters('principalIds')[copyIndex()]))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('sql-role-assign-{0}', uniqueString(parameters('principalIds')[copyIndex()]))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[guid(reference(resourceId('Microsoft.Resources/deployments', format('sql-role-definition-{0}', uniqueString(parameters('name')))), '2022-09-01').outputs.resourceId.value, parameters('principalIds')[copyIndex()], resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')))]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "roleDefinitionId": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('sql-role-definition-{0}', uniqueString(parameters('name')))), '2022-09-01').outputs.resourceId.value]" - }, - "principalId": { - "value": "[parameters('principalIds')[copyIndex()]]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "16164048892239373889" - }, - "name": "DocumentDB Database Account SQL Role Assignments.", - "description": "This module deploys a SQL Role Assignment in a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the SQL Role Assignment." - } - }, - "principalId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Id needs to be granted." - } - }, - "roleDefinitionId": { - "type": "string", - "metadata": { - "description": "Required. Id of the SQL Role Definition." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "properties": { - "principalId": "[parameters('principalId')]", - "roleDefinitionId": "[parameters('roleDefinitionId')]", - "scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName'))]" - } - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL Role Assignment was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', format('sql-role-definition-{0}', uniqueString(parameters('name'))))]" - ] - } - ], - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the SQL Role Definition and Assignment were created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_mongodbDatabases": { - "copy": { - "name": "databaseAccount_mongodbDatabases", - "count": "[length(parameters('mongodbDatabases'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-mongodb-{1}', uniqueString(deployment().name, parameters('location')), parameters('mongodbDatabases')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[parameters('mongodbDatabases')[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('mongodbDatabases')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "collections": { - "value": "[tryGet(parameters('mongodbDatabases')[copyIndex()], 'collections')]" - }, - "throughput": { - "value": "[tryGet(parameters('mongodbDatabases')[copyIndex()], 'throughput')]" - } - }, - "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.34.44.8038", - "templateHash": "918699205331356852" - }, - "name": "DocumentDB Database Account MongoDB Databases", - "description": "This module deploys a MongoDB Database within a CosmosDB Account." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the mongodb database." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Request Units per second. Setting throughput at the database level is only recommended for development/test or when workload across all collections in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "collections": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Collections in the mongodb database." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "mongodbDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]" - }, - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]" - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "mongodbDatabase_collections": { - "copy": { - "name": "mongodbDatabase_collections", - "count": "[length(parameters('collections'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-collection-{1}', uniqueString(deployment().name, parameters('name')), parameters('collections')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "mongodbDatabaseName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[parameters('collections')[copyIndex()].name]" - }, - "indexes": { - "value": "[parameters('collections')[copyIndex()].indexes]" - }, - "shardKey": { - "value": "[parameters('collections')[copyIndex()].shardKey]" - }, - "throughput": { - "value": "[tryGet(parameters('collections')[copyIndex()], 'throughput')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.34.44.8038", - "templateHash": "5747070610235343863" - }, - "name": "DocumentDB Database Account MongoDB Database Collections", - "description": "This module deploys a MongoDB Database Collection." - }, - "parameters": { - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Cosmos DB database account. Required if the template is used in a standalone deployment." - } - }, - "mongodbDatabaseName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent mongodb database. Required if the template is used in a standalone deployment." - } - }, - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the collection." - } - }, - "throughput": { - "type": "int", - "defaultValue": 400, - "metadata": { - "description": "Optional. Request Units per second. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the collection level and not at the database level." - } - }, - "indexes": { - "type": "array", - "metadata": { - "description": "Required. Indexes for the collection." - } - }, - "shardKey": { - "type": "object", - "metadata": { - "description": "Required. ShardKey for the collection." - } - } - }, - "resources": [ - { - "type": "Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]", - "properties": { - "options": "[if(contains(reference(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('databaseAccountName')), '2024-11-15').capabilities, createObject('name', 'EnableServerless')), null(), createObject('throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]", - "indexes": "[parameters('indexes')]", - "shardKey": "[parameters('shardKey')]" - } - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the mongodb database collection." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the mongodb database collection." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases/collections', parameters('databaseAccountName'), parameters('mongodbDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the mongodb database collection was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "mongodbDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the mongodb database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the mongodb database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/mongodbDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the mongodb database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_gremlinDatabases": { - "copy": { - "name": "databaseAccount_gremlinDatabases", - "count": "[length(parameters('gremlinDatabases'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-gremlin-{1}', uniqueString(deployment().name, parameters('location')), parameters('gremlinDatabases')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[parameters('gremlinDatabases')[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('gremlinDatabases')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "graphs": { - "value": "[tryGet(parameters('gremlinDatabases')[copyIndex()], 'graphs')]" - }, - "maxThroughput": { - "value": "[tryGet(parameters('gremlinDatabases')[copyIndex()], 'maxThroughput')]" - }, - "throughput": { - "value": "[tryGet(parameters('gremlinDatabases')[copyIndex()], 'throughput')]" - } - }, - "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.34.44.8038", - "templateHash": "3102415923148662010" - }, - "name": "DocumentDB Database Account Gremlin Databases", - "description": "This module deploys a Gremlin Database within a CosmosDB Account." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Gremlin database." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the Gremlin database resource." - } - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Gremlin database. Required if the template is used in a standalone deployment." - } - }, - "graphs": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Array of graphs to deploy in the Gremlin database." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`. Setting throughput at the database level is only recommended for development/test or when workload across all graphs in the shared throughput database is uniform. For best performance for large production workloads, it is recommended to set dedicated throughput (autoscale or manual) at the graph level and not at the database level." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "gremlinDatabase": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "gremlinDatabase_gremlinGraphs": { - "copy": { - "name": "gremlinDatabase_gremlinGraphs", - "count": "[length(parameters('graphs'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-gremlindb-{1}', uniqueString(deployment().name, parameters('name')), parameters('graphs')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('graphs')[copyIndex()].name]" - }, - "gremlinDatabaseName": { - "value": "[parameters('name')]" - }, - "databaseAccountName": { - "value": "[parameters('databaseAccountName')]" - }, - "indexingPolicy": { - "value": "[tryGet(parameters('graphs')[copyIndex()], 'indexingPolicy')]" - }, - "partitionKeyPaths": "[if(not(empty(parameters('graphs')[copyIndex()].partitionKeyPaths)), createObject('value', parameters('graphs')[copyIndex()].partitionKeyPaths), createObject('value', createArray()))]" - }, - "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.34.44.8038", - "templateHash": "14448207336426896249" - }, - "name": "DocumentDB Database Accounts Gremlin Databases Graphs", - "description": "This module deploys a DocumentDB Database Accounts Gremlin Database Graph." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the graph." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the Gremlin graph resource." - } - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Database Account. Required if the template is used in a standalone deployment." - } - }, - "gremlinDatabaseName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Gremlin Database. Required if the template is used in a standalone deployment." - } - }, - "indexingPolicy": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Indexing policy of the graph." - } - }, - "partitionKeyPaths": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of paths using which data within the container can be partitioned." - } - } - }, - "resources": { - "databaseAccount::gremlinDatabase": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'))]" - }, - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "gremlinGraph": { - "type": "Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}/{2}', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "resource": { - "id": "[parameters('name')]", - "indexingPolicy": "[if(not(empty(parameters('indexingPolicy'))), parameters('indexingPolicy'), null())]", - "partitionKey": { - "paths": "[if(not(empty(parameters('partitionKeyPaths'))), parameters('partitionKeyPaths'), null())]" - } - } - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the graph." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the graph." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases/graphs', parameters('databaseAccountName'), parameters('gremlinDatabaseName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the graph was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "gremlinDatabase" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the Gremlin database." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Gremlin database." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/gremlinDatabases', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Gremlin database was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_tables": { - "copy": { - "name": "databaseAccount_tables", - "count": "[length(parameters('tables'))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-table-{1}', uniqueString(deployment().name, parameters('location')), parameters('tables')[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "databaseAccountName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[parameters('tables')[copyIndex()].name]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('tables')[copyIndex()], 'tags'), parameters('tags'))]" - }, - "maxThroughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'maxThroughput')]" - }, - "throughput": { - "value": "[tryGet(parameters('tables')[copyIndex()], 'throughput')]" - } - }, - "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.34.44.8038", - "templateHash": "6386293577244138652" - }, - "name": "Azure Cosmos DB account tables", - "description": "This module deploys a table within an Azure Cosmos DB Account." - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the table." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags for the table." - } - }, - "databaseAccountName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Azure Cosmos DB account. Required if the template is used in a standalone deployment." - } - }, - "maxThroughput": { - "type": "int", - "defaultValue": 4000, - "metadata": { - "description": "Optional. Represents maximum throughput, the resource can scale up to. Cannot be set together with `throughput`. If `throughput` is set to something else than -1, this autoscale setting is ignored." - } - }, - "throughput": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Request Units per second (for example 10000). Cannot be set together with `maxThroughput`." - } - } - }, - "resources": { - "databaseAccount": { - "existing": true, - "type": "Microsoft.DocumentDB/databaseAccounts", - "apiVersion": "2024-11-15", - "name": "[parameters('databaseAccountName')]" - }, - "table": { - "type": "Microsoft.DocumentDB/databaseAccounts/tables", - "apiVersion": "2024-11-15", - "name": "[format('{0}/{1}', parameters('databaseAccountName'), parameters('name'))]", - "tags": "[parameters('tags')]", - "properties": { - "options": "[if(contains(reference('databaseAccount').capabilities, createObject('name', 'EnableServerless')), createObject(), createObject('autoscaleSettings', if(equals(parameters('throughput'), null()), createObject('maxThroughput', parameters('maxThroughput')), null()), 'throughput', parameters('throughput')))]", - "resource": { - "id": "[parameters('name')]" - } - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the table." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the table." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts/tables', parameters('databaseAccountName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the table was created in." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - }, - "databaseAccount_privateEndpoints": { - "copy": { - "name": "databaseAccount_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-databaseAccount-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '/')), coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service, copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), 'groupIds', createArray(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].service), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.13.18514", - "templateHash": "15954548978129725136" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "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.5.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": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "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." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.10.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(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": "2022-09-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.33.13.18514", - "templateHash": "5440815542537978381" - }, - "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 - } - } - }, - "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." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-11-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-11-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "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": [ - "databaseAccount" - ] - }, - "secretsExport": { - "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "keyVaultName": { - "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" - }, - "secretsToSet": { - "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryWriteKeySecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryWriteKeySecretName'), 'value', listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').primaryMasterKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'primaryReadOnlyKeySecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryReadOnlyKeySecretName'), 'value', listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').primaryReadonlyMasterKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'primaryWriteConnectionStringSecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryWriteConnectionStringSecretName'), 'value', listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').connectionStrings[0].connectionString)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'primaryReadonlyConnectionStringSecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryReadonlyConnectionStringSecretName'), 'value', listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').connectionStrings[2].connectionString)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryWriteKeySecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryWriteKeySecretName'), 'value', listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').secondaryMasterKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryReadonlyKeySecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryReadonlyKeySecretName'), 'value', listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').secondaryReadonlyMasterKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryWriteConnectionStringSecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryWriteConnectionStringSecretName'), 'value', listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').connectionStrings[1].connectionString)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryReadonlyConnectionStringSecretName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryReadonlyConnectionStringSecretName'), 'value', listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name')), '2024-11-15').connectionStrings[3].connectionString)), createArray()))]" - } - }, - "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.34.44.8038", - "templateHash": "17295277467511711636" - } - }, - "definitions": { - "secretSetType": { - "type": "object", - "properties": { - "secretResourceId": { - "type": "string", - "metadata": { - "description": "The resourceId of the exported secret." - } - }, - "secretUri": { - "type": "string", - "metadata": { - "description": "The secret URI of the exported secret." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the secret set." - } - }, - "secretToSetType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the secret to set." - } - }, - "value": { - "type": "securestring", - "metadata": { - "description": "Required. The value of the secret to set." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the secrets to set." - } - } - }, - "parameters": { - "keyVaultName": { - "type": "string", - "metadata": { - "description": "Required. The name of the Key Vault to set the ecrets in." - } - }, - "secretsToSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretToSetType" - }, - "metadata": { - "description": "Required. The secrets to set in the Key Vault." - } - } - }, - "resources": { - "keyVault": { - "existing": true, - "type": "Microsoft.KeyVault/vaults", - "apiVersion": "2023-07-01", - "name": "[parameters('keyVaultName')]" - }, - "secrets": { - "copy": { - "name": "secrets", - "count": "[length(parameters('secretsToSet'))]" - }, - "type": "Microsoft.KeyVault/vaults/secrets", - "apiVersion": "2023-07-01", - "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", - "properties": { - "value": "[parameters('secretsToSet')[copyIndex()].value]" - } - } - }, - "outputs": { - "secretsSet": { - "type": "array", - "items": { - "$ref": "#/definitions/secretSetType" - }, - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "copy": { - "count": "[length(range(0, length(coalesce(parameters('secretsToSet'), createArray()))))]", - "input": { - "secretResourceId": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretsToSet')[range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()]].name)]", - "secretUri": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUri]" - } - } - } - } - } - }, - "dependsOn": [ - "databaseAccount" - ] - } - }, - "outputs": { - "exportedSecrets": { - "$ref": "#/definitions/secretsOutputType", - "metadata": { - "description": "The references to the secrets exported to the provided Key Vault." - }, - "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the database account." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the database account." - }, - "value": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the database account was created in." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('databaseAccount', '2024-11-15', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('databaseAccount', '2024-11-15', 'full').location]" - }, - "endpoint": { - "type": "string", - "metadata": { - "description": "The endpoint of the database account." - }, - "value": "[reference('databaseAccount').documentEndpoint]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the database account." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('databaseAccount_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "containerApp", - "logAnalyticsWorkspace", - "privateDnsZonesCosmosDb", - "virtualNetwork" - ] - }, - "containerAppEnvironment": { - "condition": "[variables('containerAppEnvironmentEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('module.container-app-environment.{0}', variables('containerAppEnvironmentResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('containerAppEnvironmentResourceName')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('containerAppEnvironmentConfiguration'), 'tags'), parameters('tags'))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('containerAppEnvironmentConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "logAnalyticsResourceId": "[if(variables('useExistingWorkspace'), createObject('value', variables('existingWorkspaceResourceId')), createObject('value', listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId))]", - "publicNetworkAccess": { - "value": "Enabled" - }, - "zoneRedundant": { - "value": false - }, - "applicationInsightsConnectionString": { - "value": "[reference('applicationInsights').outputs.connectionString.value]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "subnetResourceId": "[if(variables('virtualNetworkEnabled'), createObject('value', coalesce(coalesce(tryGet(parameters('containerAppEnvironmentConfiguration'), 'subnetResourceId'), tryGet(tryGet(tryGet(reference('virtualNetwork'), 'outputs'), 'subnetResourceIds'), 'value', 3)), '')), createObject('value', ''))]" - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.36.1.42791", - "templateHash": "4058239350318625283" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string" - }, - "logAnalyticsResourceId": { - "type": "string" - }, - "tags": { - "type": "object" - }, - "publicNetworkAccess": { - "type": "string" - }, - "zoneRedundant": { - "type": "bool" - }, - "enableTelemetry": { - "type": "bool" - }, - "subnetResourceId": { - "type": "string" - }, - "applicationInsightsConnectionString": { - "type": "string" - } - }, - "variables": { - "logAnalyticsSubscription": "[split(parameters('logAnalyticsResourceId'), '/')[2]]", - "logAnalyticsResourceGroup": "[split(parameters('logAnalyticsResourceId'), '/')[4]]", - "logAnalyticsName": "[split(parameters('logAnalyticsResourceId'), '/')[8]]" - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.app.managed-environment.{0}', parameters('name')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "appLogsConfiguration": { - "value": { - "destination": "log-analytics", - "logAnalyticsConfiguration": { - "customerId": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('logAnalyticsSubscription'), variables('logAnalyticsResourceGroup')), 'Microsoft.OperationalInsights/workspaces', variables('logAnalyticsName')), '2020-08-01').customerId]", - "sharedKey": "[listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('logAnalyticsSubscription'), variables('logAnalyticsResourceGroup')), 'Microsoft.OperationalInsights/workspaces', variables('logAnalyticsName')), '2020-08-01').primarySharedKey]" - } - } - }, - "workloadProfiles": { - "value": [ - { - "name": "Consumption", - "workloadProfileType": "Consumption" - } - ] - }, - "publicNetworkAccess": { - "value": "[parameters('publicNetworkAccess')]" - }, - "appInsightsConnectionString": { - "value": "[parameters('applicationInsightsConnectionString')]" - }, - "zoneRedundant": { - "value": "[parameters('zoneRedundant')]" - }, - "infrastructureSubnetResourceId": { - "value": "[parameters('subnetResourceId')]" - }, - "internal": { - "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.35.1.17967", - "templateHash": "7921731604646231285" - }, - "name": "App ManagedEnvironments", - "description": "This module deploys an App Managed Environment (also known as a Container App Environment)." - }, - "definitions": { - "certificateType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the certificate." - } - }, - "certificateType": { - "type": "string", - "allowedValues": [ - "ImagePullTrustedCA", - "ServerSSLCertificate" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of the certificate." - } - }, - "certificateValue": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." - } - }, - "certificatePassword": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The password of the certificate." - } - }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", - "nullable": true, - "metadata": { - "description": "Optional. A key vault reference." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a certificate." - } - }, - "storageType": { - "type": "object", - "properties": { - "accessMode": { - "type": "string", - "allowedValues": [ - "ReadOnly", - "ReadWrite" - ], - "metadata": { - "description": "Required. Access mode for storage: \"ReadOnly\" or \"ReadWrite\"." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "NFS", - "SMB" - ], - "metadata": { - "description": "Required. Type of storage: \"SMB\" or \"NFS\"." - } - }, - "storageAccountName": { - "type": "string", - "metadata": { - "description": "Required. Storage account name." - } - }, - "shareName": { - "type": "string", - "metadata": { - "description": "Required. File share name." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type of the storage." - } - }, - "appLogsConfigurationType": { - "type": "object", - "properties": { - "destination": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The destination of the logs." - } - }, - "logAnalyticsConfiguration": { - "type": "object", - "properties": { - "customerId": { - "type": "string", - "metadata": { - "description": "Required. The Log Analytics Workspace ID." - } - }, - "sharedKey": { - "type": "securestring", - "metadata": { - "description": "Required. The shared key of the Log Analytics workspace." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. The configuration for Log Analytics." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the App Logs Configuration." - } - }, - "certificateKeyVaultPropertiesType": { - "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } - }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } - }, - "metadata": { - "description": "The type for the certificate's key vault properties.", - "__bicep_imported_from!": { - "sourceTemplate": "certificates/main.bicep" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container Apps Managed Environment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "appInsightsConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string." - } - }, - "daprAIConnectionString": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Application Insights connection string used by Dapr to export Service to Service communication telemetry." - } - }, - "daprAIInstrumentationKey": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Azure Monitor instrumentation key used by Dapr to export Service to Service communication telemetry." - } - }, - "dockerBridgeCidr": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "infrastructureSubnetResourceId": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if \"internal\" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "internal": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "platformReservedCidr": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "platformReservedDnsIP": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Conditional. An IP address from the IP range defined by \"platformReservedCidr\" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "peerTrafficEncryption": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not to encrypt peer traffic." - } - }, - "publicNetworkAccess": { - "type": "string", - "defaultValue": "Disabled", - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether to allow or block all public traffic." - } - }, - "zoneRedundant": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Whether or not this Managed Environment is zone-redundant." - } - }, - "certificatePassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Password of the certificate used by the custom domain." - } - }, - "certificateValue": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "Optional. Certificate to use for the custom domain. PFX or PEM." - } - }, - "dnsSuffix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. DNS suffix for the environment domain." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "openTelemetryConfiguration": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Open Telemetry configuration." - } - }, - "workloadProfiles": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Conditional. Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "infrastructureResourceGroupName": { - "type": "string", - "defaultValue": "[take(format('ME_{0}', parameters('name')), 63)]", - "metadata": { - "description": "Conditional. Name of the infrastructure resource group. If not provided, it will be set with a default value. Required if zoneRedundant is set to true to make the resource WAF compliant." - } - }, - "storages": { - "type": "array", - "items": { - "$ref": "#/definitions/storageType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The list of storages to mount on the environment." - } - }, - "certificate": { - "$ref": "#/definitions/certificateType", - "nullable": true, - "metadata": { - "description": "Optional. A Managed Environment Certificate." - } - }, - "appLogsConfiguration": { - "$ref": "#/definitions/appLogsConfigurationType", - "nullable": true, - "metadata": { - "description": "Optional. The AppLogsConfiguration for the Managed Environment." - } - } - }, - "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)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "managedEnvironment::storage": { - "copy": { - "name": "managedEnvironment::storage", - "count": "[length(coalesce(parameters('storages'), createArray()))]" - }, - "type": "Microsoft.App/managedEnvironments/storages", - "apiVersion": "2024-10-02-preview", - "name": "[format('{0}/{1}', parameters('name'), coalesce(parameters('storages'), createArray())[copyIndex()].shareName)]", - "properties": { - "nfsAzureFile": "[if(equals(coalesce(parameters('storages'), createArray())[copyIndex()].kind, 'NFS'), createObject('accessMode', coalesce(parameters('storages'), createArray())[copyIndex()].accessMode, 'server', format('{0}.file.{1}', coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName, environment().suffixes.storage), 'shareName', format('/{0}/{1}', coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName, coalesce(parameters('storages'), createArray())[copyIndex()].shareName)), null())]", - "azureFile": "[if(equals(coalesce(parameters('storages'), createArray())[copyIndex()].kind, 'SMB'), createObject('accessMode', coalesce(parameters('storages'), createArray())[copyIndex()].accessMode, 'accountName', coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName, 'accountKey', listkeys(resourceId('Microsoft.Storage/storageAccounts', coalesce(parameters('storages'), createArray())[copyIndex()].storageAccountName), '2023-01-01').keys[0].value, 'shareName', coalesce(parameters('storages'), createArray())[copyIndex()].shareName), null())]" - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-11-01", - "name": "[format('46d3xbcp.res.app-managedenvironment.{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" - } - } - } - } - }, - "managedEnvironment": { - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2024-10-02-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "appInsightsConfiguration": { - "connectionString": "[parameters('appInsightsConnectionString')]" - }, - "appLogsConfiguration": "[parameters('appLogsConfiguration')]", - "daprAIConnectionString": "[parameters('daprAIConnectionString')]", - "daprAIInstrumentationKey": "[parameters('daprAIInstrumentationKey')]", - "customDomainConfiguration": { - "certificatePassword": "[parameters('certificatePassword')]", - "certificateValue": "[if(not(empty(parameters('certificateValue'))), parameters('certificateValue'), null())]", - "dnsSuffix": "[parameters('dnsSuffix')]", - "certificateKeyVaultProperties": "[if(not(empty(tryGet(parameters('certificate'), 'certificateKeyVaultProperties'))), createObject('identity', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'identityResourceId'), 'keyVaultUrl', tryGet(parameters('certificate'), 'certificateKeyVaultProperties', 'keyVaultUrl')), null())]" - }, - "openTelemetryConfiguration": "[if(not(empty(parameters('openTelemetryConfiguration'))), parameters('openTelemetryConfiguration'), null())]", - "peerTrafficConfiguration": { - "encryption": { - "enabled": "[parameters('peerTrafficEncryption')]" - } - }, - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "vnetConfiguration": { - "internal": "[parameters('internal')]", - "infrastructureSubnetId": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('infrastructureSubnetResourceId'), null())]", - "dockerBridgeCidr": "[if(not(empty(parameters('infrastructureSubnetResourceId'))), parameters('dockerBridgeCidr'), null())]", - "platformReservedCidr": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedCidr'), null())]", - "platformReservedDnsIP": "[if(and(empty(parameters('workloadProfiles')), not(empty(parameters('infrastructureSubnetResourceId')))), parameters('platformReservedDnsIP'), null())]" - }, - "workloadProfiles": "[if(not(empty(parameters('workloadProfiles'))), parameters('workloadProfiles'), null())]", - "zoneRedundant": "[parameters('zoneRedundant')]", - "infrastructureResourceGroup": "[parameters('infrastructureResourceGroupName')]" - } - }, - "managedEnvironment_roleAssignments": { - "copy": { - "name": "managedEnvironment_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.App/managedEnvironments/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/managedEnvironments', 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": [ - "managedEnvironment" - ] - }, - "managedEnvironment_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.App/managedEnvironments/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "managedEnvironment" - ] - }, - "managedEnvironment_certificate": { - "condition": "[not(empty(parameters('certificate')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Managed-Environment-Certificate', uniqueString(deployment().name))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(parameters('certificate'), 'name'), format('cert-{0}', parameters('name')))]" - }, - "managedEnvironmentName": { - "value": "[parameters('name')]" - }, - "certificateKeyVaultProperties": { - "value": "[tryGet(parameters('certificate'), 'certificateKeyVaultProperties')]" - }, - "certificateType": { - "value": "[tryGet(parameters('certificate'), 'certificateType')]" - }, - "certificateValue": { - "value": "[tryGet(parameters('certificate'), 'certificateValue')]" - }, - "certificatePassword": { - "value": "[tryGet(parameters('certificate'), 'certificatePassword')]" - } - }, - "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.35.1.17967", - "templateHash": "18123249047188753287" - }, - "name": "App ManagedEnvironments Certificates", - "description": "This module deploys a App Managed Environment Certificate." - }, - "definitions": { - "certificateKeyVaultPropertiesType": { - "type": "object", - "properties": { - "identityResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the identity. This is the identity that will be used to access the key vault." - } - }, - "keyVaultUrl": { - "type": "string", - "metadata": { - "description": "Required. A key vault URL referencing the wildcard certificate that will be used for the custom domain." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the certificate's key vault properties." - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container Apps Managed Environment Certificate." - } - }, - "managedEnvironmentName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent app managed environment. Required if the template is used in a standalone deployment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "certificateKeyVaultProperties": { - "$ref": "#/definitions/certificateKeyVaultPropertiesType", - "nullable": true, - "metadata": { - "description": "Optional. A key vault reference to the certificate to use for the custom domain." - } - }, - "certificateType": { - "type": "string", - "nullable": true, - "allowedValues": [ - "ServerSSLCertificate", - "ImagePullTrustedCA" - ], - "metadata": { - "description": "Optional. The type of the certificate." - } - }, - "certificateValue": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The value of the certificate. PFX or PEM blob." - } - }, - "certificatePassword": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Optional. The password of the certificate." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - } - }, - "resources": { - "managedEnvironment": { - "existing": true, - "type": "Microsoft.App/managedEnvironments", - "apiVersion": "2024-10-02-preview", - "name": "[parameters('managedEnvironmentName')]" - }, - "managedEnvironmentCertificate": { - "type": "Microsoft.App/managedEnvironments/certificates", - "apiVersion": "2024-10-02-preview", - "name": "[format('{0}/{1}', parameters('managedEnvironmentName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "certificateKeyVaultProperties": "[if(not(empty(parameters('certificateKeyVaultProperties'))), createObject('identity', parameters('certificateKeyVaultProperties').identityResourceId, 'keyVaultUrl', parameters('certificateKeyVaultProperties').keyVaultUrl), null())]", - "certificateType": "[parameters('certificateType')]", - "password": "[parameters('certificatePassword')]", - "value": "[parameters('certificateValue')]" - }, - "tags": "[parameters('tags')]" - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the key values." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the key values." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments/certificates', parameters('managedEnvironmentName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the batch account was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "managedEnvironment" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Managed Environment was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('managedEnvironment', '2024-10-02-preview', 'full').location]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Managed Environment." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Managed Environment." - }, - "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('name'))]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('managedEnvironment', '2024-10-02-preview', 'full'), 'identity'), 'principalId')]" - }, - "defaultDomain": { - "type": "string", - "metadata": { - "description": "The Default domain of the Managed Environment." - }, - "value": "[reference('managedEnvironment').defaultDomain]" - }, - "staticIp": { - "type": "string", - "metadata": { - "description": "The IP address of the Managed Environment." - }, - "value": "[reference('managedEnvironment').staticIp]" - }, - "domainVerificationId": { - "type": "string", - "metadata": { - "description": "The domain verification id for custom domains." - }, - "value": "[reference('managedEnvironment').customDomainConfiguration.customDomainVerificationId]" - } - } - } - } - } - ], - "outputs": { - "resourceId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.app.managed-environment.{0}', parameters('name')), 64)), '2022-09-01').outputs.resourceId.value]" - }, - "location": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('avm.res.app.managed-environment.{0}', parameters('name')), 64)), '2022-09-01').outputs.location.value]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "logAnalyticsWorkspace", - "virtualNetwork" - ] - }, - "containerApp": { - "condition": "[variables('containerAppEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.app.container-app.{0}', variables('containerAppResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('containerAppResourceName')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'tags'), parameters('tags'))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'environmentResourceId'), reference('containerAppEnvironment').outputs.resourceId.value)]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('userAssignedIdentity').outputs.resourceId.value]" - ] - } - }, - "ingressTargetPort": { - "value": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'ingressTargetPort'), 8000)]" - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "[format('https://{0}.azurewebsites.net', variables('webSiteName'))]", - "[format('http://{0}.azurewebsites.net', variables('webSiteName'))]" - ] - } - }, - "scaleSettings": { - "value": { - "maxReplicas": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'maxReplicas'), 1)]", - "minReplicas": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'minReplicas'), 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'concurrentRequests'), '100')]" - } - } - } - ] - } - }, - "containers": { - "value": [ - { - "name": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'containerName'), 'backend')]", - "image": "[format('{0}/{1}:{2}', coalesce(tryGet(parameters('containerAppConfiguration'), 'containerImageRegistryDomain'), 'biabcontainerreg.azurecr.io'), coalesce(tryGet(parameters('containerAppConfiguration'), 'containerImageName'), 'macaebackend'), coalesce(tryGet(parameters('containerAppConfiguration'), 'containerImageTag'), 'latest'))]", - "resources": { - "cpu": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'containerCpu'), '2.0')]", - "memory": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'containerMemory'), '4.0Gi')]" - }, - "env": [ - { - "name": "COSMOSDB_ENDPOINT", - "value": "[format('https://{0}.documents.azure.com:443/', variables('cosmosDbResourceName'))]" - }, - { - "name": "COSMOSDB_DATABASE", - "value": "[variables('cosmosDbDatabaseName')]" - }, - { - "name": "COSMOSDB_CONTAINER", - "value": "[variables('cosmosDbDatabaseMemoryContainerName')]" - }, - { - "name": "AZURE_OPENAI_ENDPOINT", - "value": "[format('https://{0}.openai.azure.com/', variables('aiFoundryAiServicesResourceName'))]" - }, - { - "name": "AZURE_OPENAI_MODEL_NAME", - "value": "[variables('aiFoundryAiServicesModelDeployment').name]" - }, - { - "name": "AZURE_OPENAI_DEPLOYMENT_NAME", - "value": "[variables('aiFoundryAiServicesModelDeployment').name]" - }, - { - "name": "AZURE_OPENAI_API_VERSION", - "value": "[parameters('azureopenaiVersion')]" - }, - { - "name": "APPLICATIONINSIGHTS_INSTRUMENTATION_KEY", - "value": "[reference('applicationInsights').outputs.instrumentationKey.value]" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[reference('applicationInsights').outputs.connectionString.value]" - }, - { - "name": "AZURE_AI_SUBSCRIPTION_ID", - "value": "[subscription().subscriptionId]" - }, - { - "name": "AZURE_AI_RESOURCE_GROUP", - "value": "[resourceGroup().name]" - }, - { - "name": "AZURE_AI_PROJECT_NAME", - "value": "[variables('aiFoundryAiProjectName')]" - }, - { - "name": "FRONTEND_SITE_NAME", - "value": "[format('https://{0}.azurewebsites.net', variables('webSiteName'))]" - }, - { - "name": "AZURE_AI_AGENT_ENDPOINT", - "value": "[reference('aiFoundryAiServices').outputs.aiProjectInfo.value.apiEndpoint]" - }, - { - "name": "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME", - "value": "[variables('aiFoundryAiServicesModelDeployment').name]" - }, - { - "name": "APP_ENV", - "value": "Prod" - } - ] - } - ] - } - }, - "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.34.44.8038", - "templateHash": "18305799083153878117" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "containerType": { - "type": "object", - "properties": { - "args": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container start command arguments." - } - }, - "command": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container start command." - } - }, - "env": { - "type": "array", - "items": { - "$ref": "#/definitions/environmentVarType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container environment variables." - } - }, - "image": { - "type": "string", - "metadata": { - "description": "Required. Container image tag." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Custom container name." - } - }, - "probes": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of probes for the container." - } - }, - "resources": { - "type": "object", - "metadata": { - "description": "Required. Container resource requirements." - } - }, - "volumeMounts": { - "type": "array", - "items": { - "$ref": "#/definitions/volumeMountType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container volume mounts." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a container." - } - }, - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "runtimeType": { - "type": "object", - "properties": { - "dotnet": { - "type": "object", - "properties": { - "autoConfigureDataProtection": { - "type": "bool", - "metadata": { - "description": "Required. Enable to auto configure the ASP.NET Core Data Protection feature." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Runtime configuration for ASP.NET Core." - } - }, - "java": { - "type": "object", - "properties": { - "enableMetrics": { - "type": "bool", - "metadata": { - "description": "Required. Enable JMX core metrics for the Java app." - } - }, - "enableJavaAgent": { - "type": "bool", - "metadata": { - "description": "Required. Enable Java agent injection for the Java app." - } - }, - "loggerSettings": { - "type": "array", - "items": { - "type": "object", - "properties": { - "logger": { - "type": "string", - "metadata": { - "description": "Required. Name of the logger." - } - }, - "level": { - "type": "string", - "allowedValues": [ - "debug", - "error", - "info", - "off", - "trace", - "warn" - ], - "metadata": { - "description": "Required. Java agent logging level." - } - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Java agent logging configuration." - } - } - }, - "nullable": true, - "metadata": { - "description": "Optional. Runtime configuration for Java." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "Optional. App runtime configuration for the Container App." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "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." - } - } - }, - "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.4.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.1" - } - } - }, - "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.4.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Dev ContainerApp service type." - } - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registries": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Custom domain bindings for Container App hostnames." - } - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. Rules to restrict incoming IP address." - } - }, - "trafficLabel": { - "type": "string", - "defaultValue": "label-1", - "metadata": { - "description": "Optional. Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes." - } - }, - "trafficLatestRevision": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates that the traffic weight belongs to a latest stable revision." - } - }, - "trafficRevisionName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Name of a revision." - } - }, - "trafficWeight": { - "type": "int", - "defaultValue": 100, - "metadata": { - "description": "Optional. Traffic weight assigned to a revision." - } - }, - "dapr": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. Dapr configuration for the Container App." - } - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "$ref": "#/definitions/runtimeType", - "nullable": true, - "metadata": { - "description": "Optional. Runtime configuration for the Container App." - } - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "metadata": { - "description": "Required. List of container definitions for the Container App." - } - }, - "initContainersTemplate": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of specialized containers that run before app containers." - } - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "defaultValue": [], - "metadata": { - "description": "Optional. List of volume definitions for the Container App." - } - }, - "workloadProfileName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - } - }, - "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)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.14.2', '.', '-'), 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" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2024-10-02-preview", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[if(not(empty(parameters('dapr'))), parameters('dapr'), null())]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', if(not(empty(parameters('customDomains'))), parameters('customDomains'), null()), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', if(not(empty(parameters('ipSecurityRestrictions'))), parameters('ipSecurityRestrictions'), null()), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), createArray(createObject('label', parameters('trafficLabel'), 'latestRevision', parameters('trafficLatestRevision'), 'revisionName', parameters('trafficRevisionName'), 'weight', parameters('trafficWeight'))), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(and(parameters('includeAddOns'), not(empty(parameters('service')))), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[if(not(empty(parameters('registries'))), parameters('registries'), null())]", - "secrets": "[parameters('secrets')]", - "runtime": { - "dotnet": "[if(not(empty(tryGet(parameters('runtime'), 'dotnet'))), createObject('autoConfigureDataProtection', tryGet(parameters('runtime'), 'dotnet', 'autoConfigureDataProtection')), null())]", - "java": "[if(not(empty(tryGet(parameters('runtime'), 'java'))), createObject('enableMetrics', tryGet(parameters('runtime'), 'java', 'enableMetrics'), 'javaAgent', createObject('enabled', tryGet(parameters('runtime'), 'java', 'enableJavaAgent'), 'logging', createObject('loggerSettings', tryGet(tryGet(parameters('runtime'), 'java'), 'loggerSettings')))), null())]" - } - }, - "template": { - "containers": "[parameters('containers')]", - "initContainers": "[if(not(empty(parameters('initContainersTemplate'))), parameters('initContainersTemplate'), null())]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(and(parameters('includeAddOns'), not(empty(parameters('serviceBinds')))), parameters('serviceBinds'), null())]", - "volumes": "[if(not(empty(parameters('volumes'))), parameters('volumes'), null())]" - }, - "workloadProfileName": "[parameters('workloadProfileName')]" - } - }, - "containerApp_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.App/containerApps/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.App/containerApps/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', 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": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2024-10-02-preview', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2024-10-02-preview', 'full').location]" - } - } - } - }, - "dependsOn": [ - "aiFoundryAiServices", - "applicationInsights", - "containerAppEnvironment", - "userAssignedIdentity" - ] - }, - "containerAppMcp": { - "condition": "[variables('containerAppEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.app.container-app.{0}', variables('containerAppMcpResourceName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('containerAppMcpResourceName')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'tags'), parameters('tags'))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "environmentResourceId": { - "value": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'environmentResourceId'), reference('containerAppEnvironment').outputs.resourceId.value)]" - }, - "managedIdentities": { - "value": { - "systemAssigned": true, - "userAssignedResourceIds": [ - "[reference('userAssignedIdentity').outputs.resourceId.value]" - ] - } - }, - "ingressTargetPort": { - "value": 9000 - }, - "ingressExternal": { - "value": true - }, - "activeRevisionsMode": { - "value": "Single" - }, - "corsPolicy": { - "value": { - "allowedOrigins": [ - "[format('https://{0}.azurewebsites.net', variables('webSiteName'))]", - "[format('http://{0}.azurewebsites.net', variables('webSiteName'))]" - ] - } - }, - "scaleSettings": { - "value": { - "maxReplicas": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'maxReplicas'), 1)]", - "minReplicas": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'minReplicas'), 1)]", - "rules": [ - { - "name": "http-scaler", - "http": { - "metadata": { - "concurrentRequests": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'concurrentRequests'), '100')]" - } - } - } - ] - } - }, - "containers": { - "value": [ - { - "name": "mcp", - "image": "macaemcpacrdk.azurecr.io/macae-mac-app:t9", - "resources": { - "cpu": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'containerCpu'), '2.0')]", - "memory": "[coalesce(tryGet(parameters('containerAppConfiguration'), 'containerMemory'), '4.0Gi')]" - }, - "env": [ - { - "name": "MCP_HOST", - "value": "0.0.0.0" - }, - { - "name": "MCP_PORT", - "value": "9000" - }, - { - "name": "MCP_DEBUG", - "value": "false" - }, - { - "name": "MCP_SERVER_NAME", - "value": "MACAE MCP Server" - }, - { - "name": "MCP_ENABLE_AUTH", - "value": "true" - }, - { - "name": "AZURE_TENANT_ID", - "value": "[tenant().tenantId]" - }, - { - "name": "AZURE_CLIENT_ID", - "value": "[reference('userAssignedIdentity').outputs.clientId.value]" - }, - { - "name": "AZURE_JWKS_URI", - "value": "[format('https://login.microsoftonline.com/{0}/discovery/v2.0/keys', tenant().tenantId)]" - }, - { - "name": "AZURE_ISSUER", - "value": "[format('https://sts.windows.net/{0}/', tenant().tenantId)]" - }, - { - "name": "AZURE_AUDIENCE", - "value": "[format('api://{0}', reference('userAssignedIdentity').outputs.clientId.value)]" - }, - { - "name": "DATASET_PATH", - "value": "./datasets" - } - ] - } - ] - } - }, - "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": "13502451048865419001" - }, - "name": "Container Apps", - "description": "This module deploys a Container App." - }, - "definitions": { - "containerType": { - "type": "object", - "properties": { - "args": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container start command arguments." - } - }, - "command": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container start command." - } - }, - "env": { - "type": "array", - "items": { - "$ref": "#/definitions/environmentVarType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container environment variables." - } - }, - "image": { - "type": "string", - "metadata": { - "description": "Required. Container image tag." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Custom container name." - } - }, - "probes": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of probes for the container." - } - }, - "resources": { - "type": "object", - "metadata": { - "description": "Required. Container resource requirements." - } - }, - "volumeMounts": { - "type": "array", - "items": { - "$ref": "#/definitions/volumeMountType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Container volume mounts." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a container." - } - }, - "ingressPortMappingType": { - "type": "object", - "properties": { - "exposedPort": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." - } - }, - "external": { - "type": "bool", - "metadata": { - "description": "Required. Specifies whether the app port is accessible outside of the environment." - } - }, - "targetPort": { - "type": "int", - "metadata": { - "description": "Required. Specifies the port the container listens on." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an ingress port mapping." - } - }, - "serviceBindingType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the service." - } - }, - "serviceId": { - "type": "string", - "metadata": { - "description": "Required. The service ID." - } - } - }, - "metadata": { - "description": "The type for a service binding." - } - }, - "environmentVarType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Environment variable name." - } - }, - "secretRef": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of the Container App secret from which to pull the environment variable value." - } - }, - "value": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Non-secret environment variable value." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for an environment variable." - } - }, - "containerAppProbeType": { - "type": "object", - "properties": { - "failureThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." - } - }, - "httpGet": { - "$ref": "#/definitions/containerAppProbeHttpGetType", - "nullable": true, - "metadata": { - "description": "Optional. HTTPGet specifies the http request to perform." - } - }, - "initialDelaySeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 60, - "metadata": { - "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." - } - }, - "periodSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." - } - }, - "successThreshold": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 10, - "metadata": { - "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." - } - }, - "tcpSocket": { - "$ref": "#/definitions/containerAppProbeTcpSocketType", - "nullable": true, - "metadata": { - "description": "Optional. The TCP socket specifies an action involving a TCP port. TCP hooks not yet supported." - } - }, - "terminationGracePeriodSeconds": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." - } - }, - "timeoutSeconds": { - "type": "int", - "nullable": true, - "minValue": 1, - "maxValue": 240, - "metadata": { - "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." - } - }, - "type": { - "type": "string", - "allowedValues": [ - "Liveness", - "Readiness", - "Startup" - ], - "nullable": true, - "metadata": { - "description": "Optional. The type of probe." - } - } - }, - "metadata": { - "description": "The type for a container app probe." - } - }, - "corsPolicyType": { - "type": "object", - "properties": { - "allowCredentials": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Switch to determine whether the resource allows credentials." - } - }, - "allowedHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-headers header." - } - }, - "allowedMethods": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-methods header." - } - }, - "allowedOrigins": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-allow-origins header." - } - }, - "exposeHeaders": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-expose-headers header." - } - }, - "maxAge": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Specifies the content for the access-control-max-age header." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a CORS policy." - } - }, - "containerAppProbeHttpGetType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to. Defaults to the pod IP." - } - }, - "httpHeaders": { - "type": "array", - "items": { - "$ref": "#/definitions/containerAppProbeHttpGetHeadersItemType" - }, - "nullable": true, - "metadata": { - "description": "Optional. HTTP headers to set in the request." - } - }, - "path": { - "type": "string", - "metadata": { - "description": "Required. Path to access on the HTTP server." - } - }, - "port": { - "type": "int", - "metadata": { - "description": "Required. Name or number of the port to access on the container." - } - }, - "scheme": { - "type": "string", - "allowedValues": [ - "HTTP", - "HTTPS" - ], - "nullable": true, - "metadata": { - "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET." - } - }, - "containerAppProbeHttpGetHeadersItemType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the header." - } - }, - "value": { - "type": "string", - "metadata": { - "description": "Required. Value of the header." - } - } - }, - "metadata": { - "description": "The type for a container app probe HTTP GET header." - } - }, - "containerAppProbeTcpSocketType": { - "type": "object", - "properties": { - "host": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Host name to connect to, defaults to the pod IP." - } - }, - "port": { - "type": "int", - "minValue": 1, - "maxValue": 65535, - "metadata": { - "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." - } - } - }, - "metadata": { - "description": "The type for a container app probe TCP socket." - } - }, - "scaleType": { - "type": "object", - "properties": { - "maxReplicas": { - "type": "int", - "metadata": { - "description": "Required. The maximum number of replicas." - } - }, - "minReplicas": { - "type": "int", - "metadata": { - "description": "Required. The minimum number of replicas." - } - }, - "cooldownPeriod": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The cooldown period in seconds." - } - }, - "pollingInterval": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. The polling interval in seconds." - } - }, - "rules": { - "type": "array", - "items": { - "$ref": "#/definitions/scaleRuleType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The scaling rules." - } - } - }, - "metadata": { - "description": "The scale settings for the Container App." - } - }, - "scaleRuleType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the scaling rule." - } - }, - "custom": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The custom scaling rule." - } - }, - "azureQueue": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Azure Queue based scaling rule." - } - }, - "http": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The HTTP requests based scaling rule." - } - }, - "tcp": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The TCP based scaling rule." - } - } - }, - "metadata": { - "description": "The scaling rules for the Container App." - } - }, - "volumeMountType": { - "type": "object", - "properties": { - "mountPath": { - "type": "string", - "metadata": { - "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." - } - }, - "subPath": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." - } - }, - "volumeName": { - "type": "string", - "metadata": { - "description": "Required. This must match the Name of a Volume." - } - } - }, - "metadata": { - "description": "The type for a volume mount." - } - }, - "secretType": { - "type": "object", - "properties": { - "identity": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of a managed identity to authenticate with Azure Key Vault, or System to use a system-assigned identity." - } - }, - "keyVaultUrl": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Conditional. The URL of the Azure Key Vault secret referenced by the Container App. Required if `value` is null." - } - }, - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the container app secret." - } - }, - "value": { - "type": "securestring", - "nullable": true, - "metadata": { - "description": "Conditional. The container app secret value, if not fetched from the Key Vault. Required if `keyVaultUrl` is not null." - } - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for a secret." - } - }, - "authConfigType": { - "type": "object", - "properties": { - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "metadata": { - "__bicep_export!": true, - "description": "The type for the container app's authentication configuration." - } - }, - "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." - } - } - }, - "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.4.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.4.1" - } - } - }, - "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.4.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the Container App." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "disableIngress": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Bool to disable all ingress traffic for the container app." - } - }, - "ingressExternal": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." - } - }, - "clientCertificateMode": { - "type": "string", - "defaultValue": "ignore", - "allowedValues": [ - "accept", - "ignore", - "require" - ], - "metadata": { - "description": "Optional. Client certificate mode for mTLS." - } - }, - "corsPolicy": { - "$ref": "#/definitions/corsPolicyType", - "nullable": true, - "metadata": { - "description": "Optional. Object userd to configure CORS policy." - } - }, - "stickySessionsAffinity": { - "type": "string", - "defaultValue": "none", - "allowedValues": [ - "none", - "sticky" - ], - "metadata": { - "description": "Optional. Bool indicating if the Container App should enable session affinity." - } - }, - "ingressTransport": { - "type": "string", - "defaultValue": "auto", - "allowedValues": [ - "auto", - "http", - "http2", - "tcp" - ], - "metadata": { - "description": "Optional. Ingress transport protocol." - } - }, - "service": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/configuration/properties/service" - }, - "description": "Optional. Dev ContainerApp service type." - }, - "nullable": true - }, - "includeAddOns": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Toggle to include the service configuration." - } - }, - "additionalPortMappings": { - "type": "array", - "items": { - "$ref": "#/definitions/ingressPortMappingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Settings to expose additional ports on container app." - } - }, - "ingressAllowInsecure": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." - } - }, - "ingressTargetPort": { - "type": "int", - "defaultValue": 80, - "metadata": { - "description": "Optional. Target Port in containers for traffic from ingress." - } - }, - "scaleSettings": { - "$ref": "#/definitions/scaleType", - "defaultValue": { - "maxReplicas": 10, - "minReplicas": 3 - }, - "metadata": { - "description": "Optional. The scaling settings of the service." - } - }, - "serviceBinds": { - "type": "array", - "items": { - "$ref": "#/definitions/serviceBindingType" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of container app services bound to the app." - } - }, - "activeRevisionsMode": { - "type": "string", - "defaultValue": "Single", - "allowedValues": [ - "Multiple", - "Single" - ], - "metadata": { - "description": "Optional. Controls how active revisions are handled for the Container app." - } - }, - "environmentResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of environment." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "registries": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/configuration/properties/registries" - }, - "description": "Optional. Collection of private container registry credentials for containers used by the Container app." - }, - "nullable": true - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "customDomains": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/configuration/properties/ingress/properties/customDomains" - }, - "description": "Optional. Custom domain bindings for Container App hostnames." - }, - "nullable": true - }, - "exposedPort": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Exposed Port in containers for TCP traffic from ingress." - } - }, - "ipSecurityRestrictions": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/configuration/properties/ingress/properties/ipSecurityRestrictions" - }, - "description": "Optional. Rules to restrict incoming IP address." - }, - "nullable": true - }, - "trafficLabel": { - "type": "string", - "defaultValue": "label-1", - "metadata": { - "description": "Optional. Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes." - } - }, - "trafficLatestRevision": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Indicates that the traffic weight belongs to a latest stable revision." - } - }, - "trafficRevisionName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Name of a revision." - } - }, - "trafficWeight": { - "type": "int", - "defaultValue": 100, - "metadata": { - "description": "Optional. Traffic weight assigned to a revision." - } - }, - "dapr": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/configuration/properties/dapr" - }, - "description": "Optional. Dapr configuration for the Container App." - }, - "nullable": true - }, - "identitySettings": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/configuration/properties/identitySettings" - }, - "description": "Optional. Settings for Managed Identities that are assigned to the Container App. If a Managed Identity is not specified here, default settings will be used." - }, - "nullable": true - }, - "maxInactiveRevisions": { - "type": "int", - "defaultValue": 0, - "metadata": { - "description": "Optional. Max inactive revisions a Container App can have." - } - }, - "runtime": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/configuration/properties/runtime" - }, - "description": "Optional. Runtime configuration for the Container App." - }, - "nullable": true - }, - "containers": { - "type": "array", - "items": { - "$ref": "#/definitions/containerType" - }, - "metadata": { - "description": "Required. List of container definitions for the Container App." - } - }, - "initContainersTemplate": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/template/properties/initContainers" - }, - "description": "Optional. List of specialized containers that run before app containers." - }, - "nullable": true - }, - "secrets": { - "type": "array", - "items": { - "$ref": "#/definitions/secretType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The secrets of the Container App." - } - }, - "revisionSuffix": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. User friendly suffix that is appended to the revision name." - } - }, - "volumes": { - "type": "array", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps@2025-01-01#properties/properties/properties/template/properties/volumes" - }, - "description": "Optional. List of volume definitions for the Container App." - }, - "nullable": true - }, - "workloadProfileName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "Optional. Workload profile name to pin for container app execution." - } - }, - "authConfig": { - "$ref": "#/definitions/authConfigType", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Container App Auth configs." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "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)))))]" - } - ], - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.18.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" - } - } - } - } - }, - "containerApp": { - "type": "Microsoft.App/containerApps", - "apiVersion": "2025-01-01", - "name": "[parameters('name')]", - "tags": "[parameters('tags')]", - "location": "[parameters('location')]", - "identity": "[variables('identity')]", - "properties": { - "environmentId": "[parameters('environmentResourceId')]", - "workloadProfileName": "[parameters('workloadProfileName')]", - "template": { - "containers": "[parameters('containers')]", - "initContainers": "[if(not(empty(parameters('initContainersTemplate'))), parameters('initContainersTemplate'), null())]", - "revisionSuffix": "[parameters('revisionSuffix')]", - "scale": "[parameters('scaleSettings')]", - "serviceBinds": "[if(and(parameters('includeAddOns'), not(empty(parameters('serviceBinds')))), parameters('serviceBinds'), null())]", - "volumes": "[if(not(empty(parameters('volumes'))), parameters('volumes'), null())]" - }, - "configuration": { - "activeRevisionsMode": "[parameters('activeRevisionsMode')]", - "dapr": "[if(not(empty(parameters('dapr'))), parameters('dapr'), null())]", - "identitySettings": "[if(not(empty(parameters('identitySettings'))), parameters('identitySettings'), null())]", - "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', if(not(empty(parameters('customDomains'))), parameters('customDomains'), null()), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', if(not(empty(parameters('ipSecurityRestrictions'))), parameters('ipSecurityRestrictions'), null()), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), createArray(createObject('label', parameters('trafficLabel'), 'latestRevision', parameters('trafficLatestRevision'), 'revisionName', parameters('trafficRevisionName'), 'weight', parameters('trafficWeight'))), null()), 'transport', parameters('ingressTransport')))]", - "service": "[if(and(parameters('includeAddOns'), not(empty(parameters('service')))), parameters('service'), null())]", - "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", - "registries": "[if(not(empty(parameters('registries'))), parameters('registries'), null())]", - "secrets": "[parameters('secrets')]", - "runtime": "[if(not(empty(parameters('runtime'))), parameters('runtime'), null())]" - } - } - }, - "containerApp_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.App/containerApps/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerApp_roleAssignments": { - "copy": { - "name": "containerApp_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.App/containerApps/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', 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": [ - "containerApp" - ] - }, - "containerApp_diagnosticSettings": { - "copy": { - "name": "containerApp_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.App/containerApps/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "containerApp" - ] - }, - "containerAppAuthConfigs": { - "condition": "[not(empty(parameters('authConfig')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-auth-config', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "containerAppName": { - "value": "[parameters('name')]" - }, - "encryptionSettings": { - "value": "[tryGet(parameters('authConfig'), 'encryptionSettings')]" - }, - "globalValidation": { - "value": "[tryGet(parameters('authConfig'), 'globalValidation')]" - }, - "httpSettings": { - "value": "[tryGet(parameters('authConfig'), 'httpSettings')]" - }, - "identityProviders": { - "value": "[tryGet(parameters('authConfig'), 'identityProviders')]" - }, - "login": { - "value": "[tryGet(parameters('authConfig'), 'login')]" - }, - "platform": { - "value": "[tryGet(parameters('authConfig'), 'platform')]" - } - }, - "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": "9975390462196064744" - }, - "name": "Container App Auth Configs", - "description": "This module deploys Container App Auth Configs." - }, - "parameters": { - "containerAppName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent Container App. Required if the template is used in a standalone deployment." - } - }, - "encryptionSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/encryptionSettings" - }, - "description": "Optional. The configuration settings of the secrets references of encryption key and signing key for ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "globalValidation": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/globalValidation" - }, - "description": "Optional. The configuration settings that determines the validation flow of users using Service Authentication and/or Authorization." - }, - "nullable": true - }, - "httpSettings": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/httpSettings" - }, - "description": "Optional. The configuration settings of the HTTP requests for authentication and authorization requests made against ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "identityProviders": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/identityProviders" - }, - "description": "Optional. The configuration settings of each of the identity providers used to configure ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "login": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/login" - }, - "description": "Optional. The configuration settings of the login flow of users using ContainerApp Service Authentication/Authorization." - }, - "nullable": true - }, - "platform": { - "type": "object", - "metadata": { - "__bicep_resource_derived_type!": { - "source": "Microsoft.App/containerApps/authConfigs@2025-01-01#properties/properties/properties/platform" - }, - "description": "Optional. The configuration settings of the platform of ContainerApp Service Authentication/Authorization." - }, - "nullable": true - } - }, - "resources": { - "containerApp": { - "existing": true, - "type": "Microsoft.App/containerApps", - "apiVersion": "2025-01-01", - "name": "[parameters('containerAppName')]" - }, - "containerAppAuthConfigs": { - "type": "Microsoft.App/containerApps/authConfigs", - "apiVersion": "2025-01-01", - "name": "[format('{0}/{1}', parameters('containerAppName'), 'current')]", - "properties": { - "encryptionSettings": "[parameters('encryptionSettings')]", - "globalValidation": "[parameters('globalValidation')]", - "httpSettings": "[parameters('httpSettings')]", - "identityProviders": "[parameters('identityProviders')]", - "login": "[parameters('login')]", - "platform": "[parameters('platform')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the set of Container App Auth configs." - }, - "value": "current" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the set of Container App Auth configs." - }, - "value": "[resourceId('Microsoft.App/containerApps/authConfigs', parameters('containerAppName'), 'current')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group containing the set of Container App Auth configs." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "containerApp" - ] - } - }, - "outputs": { - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Container App." - }, - "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" - }, - "fqdn": { - "type": "string", - "metadata": { - "description": "The configuration of ingress fqdn." - }, - "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the Container App was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the Container App." - }, - "value": "[parameters('name')]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('containerApp', '2025-01-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('containerApp', '2025-01-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "containerAppEnvironment", - "userAssignedIdentity" - ] - }, - "webServerFarm": { - "condition": "[variables('webServerFarmEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-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')]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('webServerFarmConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "skuName": { - "value": "[coalesce(tryGet(parameters('webServerFarmConfiguration'), 'skuName'), 'P1v3')]" - }, - "skuCapacity": { - "value": "[coalesce(tryGet(parameters('webServerFarmConfiguration'), 'skuCapacity'), 3)]" - }, - "reserved": { - "value": true - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "kind": { - "value": "linux" - }, - "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.32.4.45862", - "templateHash": "13070013363315850466" - }, - "name": "App Service Plan", - "description": "This module deploys an App Service Plan.", - "owner": "Azure/module-maintainers" - }, - "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.4.1" - } - } - }, - "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." - } - } - }, - "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.4.1" - } - } - }, - "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.4.1" - } - } - } - }, - "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." - } - }, - "appServiceEnvironmentId": { - "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": { - "$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", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - } - }, - "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')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Web Plan Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2cc479cb-7b4d-49a8-b449-8c00fd0f0a4b')]", - "Website Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'de139f84-1756-47ae-9be6-808fbbe84772')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.web-serverfarm.{0}.{1}', replace('0.4.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" - } - } - } - } - }, - "appServicePlan": { - "type": "Microsoft.Web/serverfarms", - "apiVersion": "2022-09-01", - "name": "[parameters('name')]", - "kind": "[parameters('kind')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": { - "name": "[parameters('skuName')]", - "capacity": "[if(equals(parameters('skuName'), 'FC1'), null(), parameters('skuCapacity'))]", - "tier": "[if(equals(parameters('skuName'), 'FC1'), 'FlexConsumption', null())]" - }, - "properties": { - "workerTierName": "[parameters('workerTierName')]", - "hostingEnvironmentProfile": "[if(not(empty(parameters('appServiceEnvironmentId'))), createObject('id', parameters('appServiceEnvironmentId')), null())]", - "perSiteScaling": "[parameters('perSiteScaling')]", - "maximumElasticWorkerCount": "[parameters('maximumElasticWorkerCount')]", - "elasticScaleEnabled": "[parameters('elasticScaleEnabled')]", - "reserved": "[parameters('reserved')]", - "targetWorkerCount": "[parameters('targetWorkerCount')]", - "targetWorkerSizeId": "[parameters('targetWorkerSize')]", - "zoneRedundant": "[parameters('zoneRedundant')]" - } - }, - "appServicePlan_diagnosticSettings": { - "copy": { - "name": "appServicePlan_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "appServicePlan" - ] - }, - "appServicePlan_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.Web/serverfarms/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "appServicePlan" - ] - }, - "appServicePlan_roleAssignments": { - "copy": { - "name": "appServicePlan_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Web/serverfarms/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Web/serverfarms', 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": [ - "appServicePlan" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the app service plan was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the app service plan." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the app service plan." - }, - "value": "[resourceId('Microsoft.Web/serverfarms', parameters('name'))]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('appServicePlan', '2022-09-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "logAnalyticsWorkspace" - ] - }, - "webSite": { - "condition": "[variables('webSiteEnabled')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[take(format('avm.res.web.site.{0}', variables('webSiteName')), 64)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[variables('webSiteName')]" - }, - "tags": { - "value": "[coalesce(tryGet(parameters('webSiteConfiguration'), 'tags'), parameters('tags'))]" - }, - "location": { - "value": "[coalesce(tryGet(parameters('webSiteConfiguration'), 'location'), parameters('solutionLocation'))]" - }, - "kind": { - "value": "app,linux,container" - }, - "enableTelemetry": { - "value": "[parameters('enableTelemetry')]" - }, - "serverFarmResourceId": { - "value": "[coalesce(tryGet(parameters('webSiteConfiguration'), 'environmentResourceId'), tryGet(reference('webServerFarm'), 'outputs').resourceId.value)]" - }, - "appInsightResourceId": { - "value": "[reference('applicationInsights').outputs.resourceId.value]" - }, - "diagnosticSettings": { - "value": [ - { - "workspaceResourceId": "[if(variables('useExistingWorkspace'), variables('existingWorkspaceResourceId'), listOutputsWithSecureValues(resourceId('Microsoft.Resources/deployments', take(format('avm.res.operational-insights.workspace.{0}', variables('logAnalyticsWorkspaceResourceName')), 64)), '2022-09-01').resourceId)]" - } - ] - }, - "publicNetworkAccess": { - "value": "Enabled" - }, - "siteConfig": { - "value": { - "linuxFxVersion": "[format('DOCKER|{0}/{1}:{2}', coalesce(tryGet(parameters('webSiteConfiguration'), 'containerImageRegistryDomain'), 'biabcontainerreg.azurecr.io'), coalesce(tryGet(parameters('webSiteConfiguration'), 'containerImageName'), 'macaefrontend'), coalesce(tryGet(parameters('webSiteConfiguration'), 'containerImageTag'), 'latest'))]" - } - }, - "appSettingsKeyValuePairs": { - "value": { - "SCM_DO_BUILD_DURING_DEPLOYMENT": "true", - "DOCKER_REGISTRY_SERVER_URL": "[format('https://{0}', coalesce(tryGet(parameters('webSiteConfiguration'), 'containerImageRegistryDomain'), 'biabcontainerreg.azurecr.io'))]", - "WEBSITES_PORT": "3000", - "WEBSITES_CONTAINER_START_TIME_LIMIT": "1800", - "BACKEND_API_URL": "[format('https://{0}', reference('containerApp').outputs.fqdn.value)]", - "AUTH_ENABLED": "false", - "APP_ENV": "Prod" - } - } - }, - "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.33.93.31351", - "templateHash": "2522527858358792357" - }, - "name": "Web/Function Apps", - "description": "This module deploys a Web or Function App." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "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": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the site." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "functionapp", - "functionapp,linux", - "functionapp,workflowapp", - "functionapp,workflowapp,linux", - "functionapp,linux,container", - "functionapp,linux,container,azurecontainerapps", - "app,linux", - "app", - "linux,api", - "api", - "app,linux,container", - "app,container,windows" - ], - "metadata": { - "description": "Required. Type of site to deploy." - } - }, - "serverFarmResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the app service plan to use for the site." - } - }, - "managedEnvironmentId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Azure Resource Manager ID of the customers selected Managed Environment on which to host this app." - } - }, - "httpsOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Configures a site to accept only HTTPS requests. Issues redirect for HTTP requests." - } - }, - "clientAffinityEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If client affinity is enabled." - } - }, - "appServiceEnvironmentResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the app service environment to use for this resource." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "keyVaultAccessIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the assigned identity to be used to access a key vault with." - } - }, - "storageAccountRequired": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Checks if Customer provided storage account is required." - } - }, - "virtualNetworkSubnetId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration. This must be of the form /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}." - } - }, - "vnetContentShareEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. To enable accessing content over virtual network." - } - }, - "vnetImagePullEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. To enable pulling image over Virtual Network." - } - }, - "vnetRouteAllEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Virtual Network Route All enabled. This causes all outbound traffic to have Virtual Network Security Groups and User Defined Routes applied." - } - }, - "scmSiteAlsoStopped": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Stop SCM (KUDU) site when the app is stopped." - } - }, - "siteConfig": { - "type": "object", - "defaultValue": { - "alwaysOn": true, - "minTlsVersion": "1.2", - "ftpsState": "FtpsOnly" - }, - "metadata": { - "description": "Optional. The site config object. The defaults are set to the following values: alwaysOn: true, minTlsVersion: '1.2', ftpsState: 'FtpsOnly'." - } - }, - "functionAppConfig": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Function App configuration object." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions." - } - }, - "storageAccountUseIdentityAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'." - } - }, - "webConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Site Config, Web settings to deploy." - } - }, - "msDeployConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The extension MSDeployment configuration." - } - }, - "appInsightResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the app insight to leverage for this resource." - } - }, - "appSettingsKeyValuePairs": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The app settings-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." - } - }, - "authSettingV2Configuration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The auth settings V2 configuration." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "logsConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The logs settings configuration." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." - } - }, - "slots": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Configuration for deployment slots for an app." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "enableTelemetry": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "clientCertEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. To enable client certificate authentication (TLS mutual authentication)." - } - }, - "clientCertExclusionPaths": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client certificate authentication comma-separated exclusion paths." - } - }, - "clientCertMode": { - "type": "string", - "defaultValue": "Optional", - "allowedValues": [ - "Optional", - "OptionalInteractiveUser", - "Required" - ], - "metadata": { - "description": "Optional. This composes with ClientCertEnabled setting.\n- ClientCertEnabled=false means ClientCert is ignored.\n- ClientCertEnabled=true and ClientCertMode=Required means ClientCert is required.\n- ClientCertEnabled=true and ClientCertMode=Optional means ClientCert is optional or accepted.\n" - } - }, - "cloningInfo": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. If specified during app creation, the app is cloned from a source app." - } - }, - "containerSize": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Size of the function container." - } - }, - "dailyMemoryTimeQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum allowed daily memory-time quota (applicable on dynamic apps only)." - } - }, - "enabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Setting this value to false disables the app (takes the app offline)." - } - }, - "hostNameSslStates": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Hostname SSL states are used to manage the SSL bindings for app's hostnames." - } - }, - "hyperV": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Hyper-V sandbox." - } - }, - "redundancyMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "ActiveActive", - "Failover", - "GeoRedundant", - "Manual", - "None" - ], - "metadata": { - "description": "Optional. Site redundancy mode." - } - }, - "basicPublishingCredentialsPolicies": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The site publishing credential policy names which are associated with the sites." - } - }, - "hybridConnectionRelays": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Names of hybrid connection relays to connect app with." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set." - } - }, - "e2eEncryptionEnabled": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. End to End Encryption Setting." - } - } - }, - "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)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Web Plan Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2cc479cb-7b4d-49a8-b449-8c00fd0f0a4b')]", - "Website Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'de139f84-1756-47ae-9be6-808fbbe84772')]" - } - }, - "resources": { - "avmTelemetry": { - "condition": "[parameters('enableTelemetry')]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.web-site.{0}.{1}', replace('0.15.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" - } - } - } - } - }, - "app": { - "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "managedEnvironmentId": "[if(not(empty(parameters('managedEnvironmentId'))), parameters('managedEnvironmentId'), null())]", - "serverFarmId": "[parameters('serverFarmResourceId')]", - "clientAffinityEnabled": "[parameters('clientAffinityEnabled')]", - "httpsOnly": "[parameters('httpsOnly')]", - "hostingEnvironmentProfile": "[if(not(empty(parameters('appServiceEnvironmentResourceId'))), createObject('id', parameters('appServiceEnvironmentResourceId')), null())]", - "storageAccountRequired": "[parameters('storageAccountRequired')]", - "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", - "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", - "siteConfig": "[parameters('siteConfig')]", - "functionAppConfig": "[parameters('functionAppConfig')]", - "clientCertEnabled": "[parameters('clientCertEnabled')]", - "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", - "clientCertMode": "[parameters('clientCertMode')]", - "cloningInfo": "[parameters('cloningInfo')]", - "containerSize": "[parameters('containerSize')]", - "dailyMemoryTimeQuota": "[parameters('dailyMemoryTimeQuota')]", - "enabled": "[parameters('enabled')]", - "hostNameSslStates": "[parameters('hostNameSslStates')]", - "hyperV": "[parameters('hyperV')]", - "redundancyMode": "[parameters('redundancyMode')]", - "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(not(empty(parameters('privateEndpoints'))), 'Disabled', 'Enabled'))]", - "vnetContentShareEnabled": "[parameters('vnetContentShareEnabled')]", - "vnetImagePullEnabled": "[parameters('vnetImagePullEnabled')]", - "vnetRouteAllEnabled": "[parameters('vnetRouteAllEnabled')]", - "scmSiteAlsoStopped": "[parameters('scmSiteAlsoStopped')]", - "endToEndEncryptionEnabled": "[parameters('e2eEncryptionEnabled')]" - } - }, - "app_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.Web/sites/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "app" - ] - }, - "app_diagnosticSettings": { - "copy": { - "name": "app_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Web/sites/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "app" - ] - }, - "app_roleAssignments": { - "copy": { - "name": "app_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Web/sites/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Web/sites', 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": [ - "app" - ] - }, - "app_appsettings": { - "condition": "[or(or(not(empty(parameters('appSettingsKeyValuePairs'))), not(empty(parameters('appInsightResourceId')))), not(empty(parameters('storageAccountResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Site-Config-AppSettings', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appName": { - "value": "[parameters('name')]" - }, - "kind": { - "value": "[parameters('kind')]" - }, - "storageAccountResourceId": { - "value": "[parameters('storageAccountResourceId')]" - }, - "storageAccountUseIdentityAuthentication": { - "value": "[parameters('storageAccountUseIdentityAuthentication')]" - }, - "appInsightResourceId": { - "value": "[parameters('appInsightResourceId')]" - }, - "appSettingsKeyValuePairs": { - "value": "[parameters('appSettingsKeyValuePairs')]" - }, - "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites', parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites', parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" - }, - "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.33.93.31351", - "templateHash": "12262977018813780856" - }, - "name": "Site App Settings", - "description": "This module deploys a Site App Setting." - }, - "parameters": { - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent site resource. Required if the template is used in a standalone deployment." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "functionapp", - "functionapp,linux", - "functionapp,workflowapp", - "functionapp,workflowapp,linux", - "functionapp,linux,container", - "functionapp,linux,container,azurecontainerapps", - "app,linux", - "app", - "linux,api", - "api", - "app,linux,container", - "app,container,windows" - ], - "metadata": { - "description": "Required. Type of site to deploy." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions." - } - }, - "storageAccountUseIdentityAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'." - } - }, - "appInsightResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the app insight to leverage for this resource." - } - }, - "appSettingsKeyValuePairs": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." - } - }, - "currentAppSettings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The current app settings." - } - } - }, - "resources": { - "app": { - "existing": true, - "type": "Microsoft.Web/sites", - "apiVersion": "2023-12-01", - "name": "[parameters('appName')]" - }, - "appInsight": { - "condition": "[not(empty(parameters('appInsightResourceId')))]", - "existing": true, - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "subscriptionId": "[split(parameters('appInsightResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('appInsightResourceId'), '/')[4]]", - "name": "[last(split(parameters('appInsightResourceId'), '/'))]" - }, - "storageAccount": { - "condition": "[not(empty(parameters('storageAccountResourceId')))]", - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-05-01", - "subscriptionId": "[split(parameters('storageAccountResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('storageAccountResourceId'), '/')[4]]", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" - }, - "appSettings": { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), 'appsettings')]", - "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(parameters('storageAccountResourceId'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('storageAccountResourceId'), '/')[2], split(parameters('storageAccountResourceId'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2023-05-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(parameters('storageAccountResourceId'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob), createObject('AzureWebJobsStorage__queueServiceUri', reference('storageAccount').primaryEndpoints.queue), createObject('AzureWebJobsStorage__tableServiceUri', reference('storageAccount').primaryEndpoints.table)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", - "dependsOn": [ - "appInsight", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the site config." - }, - "value": "appsettings" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the site config." - }, - "value": "[resourceId('Microsoft.Web/sites/config', parameters('appName'), 'appsettings')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the site config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "app" - ] - }, - "app_authsettingsv2": { - "condition": "[not(empty(parameters('authSettingV2Configuration')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Site-Config-AuthSettingsV2', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appName": { - "value": "[parameters('name')]" - }, - "kind": { - "value": "[parameters('kind')]" - }, - "authSettingV2Configuration": { - "value": "[coalesce(parameters('authSettingV2Configuration'), createObject())]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "1129994114817101549" - }, - "name": "Site Auth Settings V2 Config", - "description": "This module deploys a Site Auth Settings V2 Configuration." - }, - "parameters": { - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent site resource. Required if the template is used in a standalone deployment." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "functionapp", - "functionapp,linux", - "functionapp,workflowapp", - "functionapp,workflowapp,linux", - "functionapp,linux,container", - "functionapp,linux,container,azurecontainerapps", - "app,linux", - "app", - "linux,api", - "api", - "app,linux,container", - "app,container,windows" - ], - "metadata": { - "description": "Required. Type of site to deploy." - } - }, - "authSettingV2Configuration": { - "type": "object", - "metadata": { - "description": "Required. The auth settings V2 configuration." - } - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), 'authsettingsV2')]", - "kind": "[parameters('kind')]", - "properties": "[parameters('authSettingV2Configuration')]" - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the site config." - }, - "value": "authsettingsV2" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the site config." - }, - "value": "[resourceId('Microsoft.Web/sites/config', parameters('appName'), 'authsettingsV2')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the site config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "app" - ] - }, - "app_logssettings": { - "condition": "[not(empty(coalesce(parameters('logsConfiguration'), createObject())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Site-Config-Logs', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appName": { - "value": "[parameters('name')]" - }, - "logsConfiguration": { - "value": "[parameters('logsConfiguration')]" - } - }, - "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.33.93.31351", - "templateHash": "17967336872376441757" - }, - "name": "Site logs Config", - "description": "This module deploys a Site logs Configuration." - }, - "parameters": { - "appName": { - "type": "string", - "metadata": { - "description": "Required. The name of the parent site resource." - } - }, - "logsConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The logs settings configuration." - } - } - }, - "resources": { - "app": { - "existing": true, - "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", - "name": "[parameters('appName')]" - }, - "webSettings": { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), 'logs')]", - "kind": "string", - "properties": "[parameters('logsConfiguration')]" - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the site config." - }, - "value": "logs" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the site config." - }, - "value": "[resourceId('Microsoft.Web/sites/config', parameters('appName'), 'logs')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the site config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "app", - "app_appsettings" - ] - }, - "app_websettings": { - "condition": "[not(empty(coalesce(parameters('webConfiguration'), createObject())))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Site-Config-Web', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appName": { - "value": "[parameters('name')]" - }, - "webConfiguration": { - "value": "[parameters('webConfiguration')]" - } - }, - "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.33.93.31351", - "templateHash": "15058680643544097487" - }, - "name": "Site Web Config", - "description": "This module deploys web settings configuration available under sites/config name: web." - }, - "parameters": { - "appName": { - "type": "string", - "metadata": { - "description": "Required. The name of the parent site resource." - } - }, - "webConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Site Config, Web settings to deploy." - } - } - }, - "resources": { - "app": { - "existing": true, - "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", - "name": "[parameters('appName')]" - }, - "webSettings": { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), 'web')]", - "kind": "string", - "properties": "[parameters('webConfiguration')]" - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the site config." - }, - "value": "web" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the site config." - }, - "value": "[resourceId('Microsoft.Web/sites/config', parameters('appName'), 'web')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the site config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "app" - ] - }, - "extension_msdeploy": { - "condition": "[not(empty(parameters('msDeployConfiguration')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Site-Extension-MSDeploy', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appName": { - "value": "[parameters('name')]" - }, - "msDeployConfiguration": { - "value": "[coalesce(parameters('msDeployConfiguration'), createObject())]" - } - }, - "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.33.93.31351", - "templateHash": "14895622660217616811" - }, - "name": "Site Deployment Extension ", - "description": "This module deploys a Site extension for MSDeploy." - }, - "parameters": { - "appName": { - "type": "string", - "metadata": { - "description": "Required. The name of the parent site resource." - } - }, - "msDeployConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Sets the MSDeployment Properties." - } - } - }, - "resources": { - "app": { - "existing": true, - "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", - "name": "[parameters('appName')]" - }, - "msdeploy": { - "type": "Microsoft.Web/sites/extensions", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), 'MSDeploy')]", - "kind": "MSDeploy", - "properties": "[parameters('msDeployConfiguration')]" - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the MSDeploy Package." - }, - "value": "MSDeploy" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Site Extension." - }, - "value": "[resourceId('Microsoft.Web/sites/extensions', parameters('appName'), 'MSDeploy')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the site config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "app" - ] - }, - "app_slots": { - "copy": { - "name": "app_slots", - "count": "[length(coalesce(parameters('slots'), createArray()))]", - "mode": "serial", - "batchSize": 1 - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Slot-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('slots'), createArray())[copyIndex()].name)]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(parameters('slots'), createArray())[copyIndex()].name]" - }, - "appName": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "kind": { - "value": "[parameters('kind')]" - }, - "serverFarmResourceId": { - "value": "[parameters('serverFarmResourceId')]" - }, - "httpsOnly": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'httpsOnly'), parameters('httpsOnly'))]" - }, - "appServiceEnvironmentResourceId": { - "value": "[parameters('appServiceEnvironmentResourceId')]" - }, - "clientAffinityEnabled": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'clientAffinityEnabled'), parameters('clientAffinityEnabled'))]" - }, - "managedIdentities": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'managedIdentities'), parameters('managedIdentities'))]" - }, - "keyVaultAccessIdentityResourceId": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'keyVaultAccessIdentityResourceId'), parameters('keyVaultAccessIdentityResourceId'))]" - }, - "storageAccountRequired": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'storageAccountRequired'), parameters('storageAccountRequired'))]" - }, - "virtualNetworkSubnetId": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'virtualNetworkSubnetId'), parameters('virtualNetworkSubnetId'))]" - }, - "siteConfig": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'siteConfig'), parameters('siteConfig'))]" - }, - "functionAppConfig": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'functionAppConfig'), parameters('functionAppConfig'))]" - }, - "storageAccountResourceId": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'storageAccountResourceId'), parameters('storageAccountResourceId'))]" - }, - "storageAccountUseIdentityAuthentication": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'storageAccountUseIdentityAuthentication'), parameters('storageAccountUseIdentityAuthentication'))]" - }, - "appInsightResourceId": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'appInsightResourceId'), parameters('appInsightResourceId'))]" - }, - "authSettingV2Configuration": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'authSettingV2Configuration'), parameters('authSettingV2Configuration'))]" - }, - "msDeployConfiguration": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'msDeployConfiguration'), parameters('msDeployConfiguration'))]" - }, - "diagnosticSettings": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'diagnosticSettings')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "appSettingsKeyValuePairs": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'appSettingsKeyValuePairs'), parameters('appSettingsKeyValuePairs'))]" - }, - "basicPublishingCredentialsPolicies": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'basicPublishingCredentialsPolicies'), parameters('basicPublishingCredentialsPolicies'))]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateEndpoints": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'privateEndpoints'), createArray())]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "clientCertEnabled": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'clientCertEnabled')]" - }, - "clientCertExclusionPaths": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'clientCertExclusionPaths')]" - }, - "clientCertMode": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'clientCertMode')]" - }, - "cloningInfo": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'cloningInfo')]" - }, - "containerSize": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'containerSize')]" - }, - "customDomainVerificationId": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'customDomainVerificationId')]" - }, - "dailyMemoryTimeQuota": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'dailyMemoryTimeQuota')]" - }, - "enabled": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'enabled')]" - }, - "hostNameSslStates": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'hostNameSslStates')]" - }, - "hyperV": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'hyperV')]" - }, - "publicNetworkAccess": { - "value": "[coalesce(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'publicNetworkAccess'), if(or(not(empty(tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'privateEndpoints'))), not(empty(parameters('privateEndpoints')))), 'Disabled', 'Enabled'))]" - }, - "redundancyMode": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'redundancyMode')]" - }, - "vnetContentShareEnabled": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'vnetContentShareEnabled')]" - }, - "vnetImagePullEnabled": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'vnetImagePullEnabled')]" - }, - "vnetRouteAllEnabled": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'vnetRouteAllEnabled')]" - }, - "hybridConnectionRelays": { - "value": "[tryGet(coalesce(parameters('slots'), createArray())[copyIndex()], 'hybridConnectionRelays')]" - } - }, - "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.33.93.31351", - "templateHash": "4067755327331248181" - }, - "name": "Web/Function App Deployment Slots", - "description": "This module deploys a Web or Function App Deployment Slot." - }, - "definitions": { - "privateEndpointOutputType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - } - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - } - }, - "groupId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The group Id for the private endpoint Group." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "A list of private IP addresses of the private endpoint." - } - } - } - }, - "metadata": { - "description": "The custom DNS configurations of the private endpoint." - } - }, - "networkInterfaceResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The IDs of the network interfaces associated with the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "_1.privateEndpointCustomDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointIpConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "_1.privateEndpointPrivateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "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": "Required. The private DNS Zone Groups to associate the Private Endpoint. A DNS Zone Group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "diagnosticSettingFullType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the diagnostic setting." - } - }, - "logCategoriesAndGroups": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." - } - }, - "categoryGroup": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." - } - }, - "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 logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." - } - }, - "metricCategories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "category": { - "type": "string", - "metadata": { - "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." - } - }, - "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 both logs & metrics are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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." - } - } - }, - "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.5.1" - } - } - }, - "managedIdentityAllType": { - "type": "object", - "properties": { - "systemAssigned": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enables system assigned managed identity on the resource." - } - }, - "userAssignedResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a managed identity configuration. To be used if both a system-assigned & user-assigned identities are supported by the resource provider.", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "privateEndpointSingleServiceType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private Endpoint." - } - }, - "location": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The location to deploy the Private Endpoint to." - } - }, - "privateLinkServiceConnectionName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the private link connection to create." - } - }, - "service": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The subresource to deploy the Private Endpoint for. For example \"vault\" for a Key Vault Private Endpoint." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "resourceGroupResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS Zone Group to configure for the Private Endpoint." - } - }, - "isManualConnection": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. If Manual Private Link Connection is required." - } - }, - "manualConnectionRequestMessage": { - "type": "string", - "nullable": true, - "maxLength": 140, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the Private Endpoint. This will be used to map to the first-party Service endpoints." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the Private Endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the Private Endpoint." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/Resource Groups in this deployment." - } - }, - "enableTelemetry": { - "type": "bool", - "nullable": true, - "metadata": { - "description": "Optional. Enable/Disable usage telemetry for module." - } - } - }, - "metadata": { - "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", - "__bicep_imported_from!": { - "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the slot." - } - }, - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent site resource. Required if the template is used in a standalone deployment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "functionapp", - "functionapp,linux", - "functionapp,workflowapp", - "functionapp,workflowapp,linux", - "functionapp,linux,container", - "functionapp,linux,container,azurecontainerapps", - "app,linux", - "app", - "linux,api", - "api", - "app,linux,container", - "app,container,windows" - ], - "metadata": { - "description": "Required. Type of site to deploy." - } - }, - "serverFarmResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the app service plan to use for the slot." - } - }, - "httpsOnly": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Configures a slot to accept only HTTPS requests. Issues redirect for HTTP requests." - } - }, - "clientAffinityEnabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. If client affinity is enabled." - } - }, - "appServiceEnvironmentResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the app service environment to use for this resource." - } - }, - "managedIdentities": { - "$ref": "#/definitions/managedIdentityAllType", - "nullable": true, - "metadata": { - "description": "Optional. The managed identity definition for this resource." - } - }, - "keyVaultAccessIdentityResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource ID of the assigned identity to be used to access a key vault with." - } - }, - "storageAccountRequired": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Checks if Customer provided storage account is required." - } - }, - "virtualNetworkSubnetId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration. This must be of the form /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}." - } - }, - "siteConfig": { - "type": "object", - "defaultValue": { - "alwaysOn": true - }, - "metadata": { - "description": "Optional. The site config object." - } - }, - "functionAppConfig": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The Function App config object." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions." - } - }, - "storageAccountUseIdentityAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'." - } - }, - "appInsightResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the app insight to leverage for this resource." - } - }, - "appSettingsKeyValuePairs": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The app settings-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." - } - }, - "authSettingV2Configuration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The auth settings V2 configuration." - } - }, - "msDeployConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The extension MSDeployment configuration." - } - }, - "lock": { - "$ref": "#/definitions/lockType", - "nullable": true, - "metadata": { - "description": "Optional. The lock settings of the service." - } - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointSingleServiceType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Configuration details for private endpoints." - } - }, - "tags": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Tags of the resource." - } - }, - "roleAssignments": { - "type": "array", - "items": { - "$ref": "#/definitions/roleAssignmentType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Array of role assignments to create." - } - }, - "diagnosticSettings": { - "type": "array", - "items": { - "$ref": "#/definitions/diagnosticSettingFullType" - }, - "nullable": true, - "metadata": { - "description": "Optional. The diagnostic settings of the service." - } - }, - "clientCertEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. To enable client certificate authentication (TLS mutual authentication)." - } - }, - "clientCertExclusionPaths": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Client certificate authentication comma-separated exclusion paths." - } - }, - "clientCertMode": { - "type": "string", - "defaultValue": "Optional", - "allowedValues": [ - "Optional", - "OptionalInteractiveUser", - "Required" - ], - "metadata": { - "description": "Optional. This composes with ClientCertEnabled setting.

- ClientCertEnabled: false means ClientCert is ignored.

- ClientCertEnabled: true and ClientCertMode: Required means ClientCert is required.

- ClientCertEnabled: true and ClientCertMode: Optional means ClientCert is optional or accepted." - } - }, - "cloningInfo": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. If specified during app creation, the app is cloned from a source app." - } - }, - "containerSize": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Size of the function container." - } - }, - "customDomainVerificationId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Unique identifier that verifies the custom domains assigned to the app. Customer will add this ID to a txt record for verification." - } - }, - "dailyMemoryTimeQuota": { - "type": "int", - "nullable": true, - "metadata": { - "description": "Optional. Maximum allowed daily memory-time quota (applicable on dynamic apps only)." - } - }, - "enabled": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Setting this value to false disables the app (takes the app offline)." - } - }, - "hostNameSslStates": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Hostname SSL states are used to manage the SSL bindings for app's hostnames." - } - }, - "hyperV": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Hyper-V sandbox." - } - }, - "publicNetworkAccess": { - "type": "string", - "nullable": true, - "allowedValues": [ - "Enabled", - "Disabled" - ], - "metadata": { - "description": "Optional. Allow or block all public traffic." - } - }, - "redundancyMode": { - "type": "string", - "defaultValue": "None", - "allowedValues": [ - "ActiveActive", - "Failover", - "GeoRedundant", - "Manual", - "None" - ], - "metadata": { - "description": "Optional. Site redundancy mode." - } - }, - "basicPublishingCredentialsPolicies": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. The site publishing credential policy names which are associated with the site slot." - } - }, - "vnetContentShareEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. To enable accessing content over virtual network." - } - }, - "vnetImagePullEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. To enable pulling image over Virtual Network." - } - }, - "vnetRouteAllEnabled": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. Virtual Network Route All enabled. This causes all outbound traffic to have Virtual Network Security Groups and User Defined Routes applied." - } - }, - "hybridConnectionRelays": { - "type": "array", - "nullable": true, - "metadata": { - "description": "Optional. Names of hybrid connection relays to connect app with." - } - } - }, - "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)))))]" - } - ], - "enableReferencedModulesTelemetry": false, - "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", - "builtInRoleNames": { - "App Compliance Automation Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f37683f-2463-46b6-9ce7-9b788b988ba2')]", - "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", - "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", - "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", - "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", - "Web Plan Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2cc479cb-7b4d-49a8-b449-8c00fd0f0a4b')]", - "Website Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'de139f84-1756-47ae-9be6-808fbbe84772')]" - } - }, - "resources": { - "app": { - "existing": true, - "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", - "name": "[parameters('appName')]" - }, - "slot": { - "type": "Microsoft.Web/sites/slots", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), parameters('name'))]", - "location": "[parameters('location')]", - "kind": "[parameters('kind')]", - "tags": "[parameters('tags')]", - "identity": "[variables('identity')]", - "properties": { - "serverFarmId": "[parameters('serverFarmResourceId')]", - "clientAffinityEnabled": "[parameters('clientAffinityEnabled')]", - "httpsOnly": "[parameters('httpsOnly')]", - "hostingEnvironmentProfile": "[if(not(empty(parameters('appServiceEnvironmentResourceId'))), createObject('id', parameters('appServiceEnvironmentResourceId')), null())]", - "storageAccountRequired": "[parameters('storageAccountRequired')]", - "keyVaultReferenceIdentity": "[parameters('keyVaultAccessIdentityResourceId')]", - "virtualNetworkSubnetId": "[parameters('virtualNetworkSubnetId')]", - "siteConfig": "[parameters('siteConfig')]", - "functionAppConfig": "[parameters('functionAppConfig')]", - "clientCertEnabled": "[parameters('clientCertEnabled')]", - "clientCertExclusionPaths": "[parameters('clientCertExclusionPaths')]", - "clientCertMode": "[parameters('clientCertMode')]", - "cloningInfo": "[parameters('cloningInfo')]", - "containerSize": "[parameters('containerSize')]", - "customDomainVerificationId": "[parameters('customDomainVerificationId')]", - "dailyMemoryTimeQuota": "[parameters('dailyMemoryTimeQuota')]", - "enabled": "[parameters('enabled')]", - "hostNameSslStates": "[parameters('hostNameSslStates')]", - "hyperV": "[parameters('hyperV')]", - "publicNetworkAccess": "[parameters('publicNetworkAccess')]", - "redundancyMode": "[parameters('redundancyMode')]", - "vnetContentShareEnabled": "[parameters('vnetContentShareEnabled')]", - "vnetImagePullEnabled": "[parameters('vnetImagePullEnabled')]", - "vnetRouteAllEnabled": "[parameters('vnetRouteAllEnabled')]" - } - }, - "slot_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.Web/sites/{0}/slots/{1}', parameters('appName'), parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "slot" - ] - }, - "slot_diagnosticSettings": { - "copy": { - "name": "slot_diagnosticSettings", - "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" - }, - "type": "Microsoft.Insights/diagnosticSettings", - "apiVersion": "2021-05-01-preview", - "scope": "[format('Microsoft.Web/sites/{0}/slots/{1}', parameters('appName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", - "properties": { - "copy": [ - { - "name": "metrics", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", - "input": { - "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", - "timeGrain": null - } - }, - { - "name": "logs", - "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", - "input": { - "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", - "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", - "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" - } - } - ], - "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", - "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", - "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", - "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", - "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", - "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" - }, - "dependsOn": [ - "slot" - ] - }, - "slot_roleAssignments": { - "copy": { - "name": "slot_roleAssignments", - "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" - }, - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Web/sites/{0}/slots/{1}', parameters('appName'), parameters('name'))]", - "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Web/sites/slots', parameters('appName'), 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": [ - "slot" - ] - }, - "slot_appsettings": { - "condition": "[or(or(not(empty(parameters('appSettingsKeyValuePairs'))), not(empty(parameters('appInsightResourceId')))), not(empty(parameters('storageAccountResourceId'))))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Slot-{1}-Config-AppSettings', uniqueString(deployment().name, parameters('location')), parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "slotName": { - "value": "[parameters('name')]" - }, - "appName": { - "value": "[parameters('appName')]" - }, - "kind": { - "value": "[parameters('kind')]" - }, - "storageAccountResourceId": { - "value": "[parameters('storageAccountResourceId')]" - }, - "storageAccountUseIdentityAuthentication": { - "value": "[parameters('storageAccountUseIdentityAuthentication')]" - }, - "appInsightResourceId": { - "value": "[parameters('appInsightResourceId')]" - }, - "appSettingsKeyValuePairs": { - "value": "[parameters('appSettingsKeyValuePairs')]" - }, - "currentAppSettings": "[if(not(empty(resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name')))), createObject('value', list(format('{0}/config/appsettings', resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name'))), '2023-12-01').properties), createObject('value', createObject()))]" - }, - "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.33.93.31351", - "templateHash": "18192409627790392598" - }, - "name": "Site Slot App Settings", - "description": "This module deploys a Site Slot App Setting." - }, - "parameters": { - "slotName": { - "type": "string", - "metadata": { - "description": "Required. Slot name to be configured." - } - }, - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent site resource. Required if the template is used in a standalone deployment." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "functionapp", - "functionapp,linux", - "functionapp,workflowapp", - "functionapp,workflowapp,linux", - "functionapp,linux,container", - "functionapp,linux,container,azurecontainerapps", - "app,linux", - "app", - "linux,api", - "api", - "app,linux,container", - "app,container,windows" - ], - "metadata": { - "description": "Required. Type of site to deploy." - } - }, - "storageAccountResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions." - } - }, - "storageAccountUseIdentityAuthentication": { - "type": "bool", - "defaultValue": false, - "metadata": { - "description": "Optional. If the provided storage account requires Identity based authentication ('allowSharedKeyAccess' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is 'Storage Blob Data Owner'." - } - }, - "appInsightResourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Resource ID of the app insight to leverage for this resource." - } - }, - "appSettingsKeyValuePairs": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING." - } - }, - "currentAppSettings": { - "type": "object", - "defaultValue": {}, - "metadata": { - "description": "Optional. The current app settings." - } - } - }, - "resources": { - "app::slot": { - "existing": true, - "type": "Microsoft.Web/sites/slots", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), parameters('slotName'))]" - }, - "app": { - "existing": true, - "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", - "name": "[parameters('appName')]" - }, - "appInsight": { - "condition": "[not(empty(parameters('appInsightResourceId')))]", - "existing": true, - "type": "Microsoft.Insights/components", - "apiVersion": "2020-02-02", - "subscriptionId": "[split(parameters('appInsightResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('appInsightResourceId'), '/')[4]]", - "name": "[last(split(parameters('appInsightResourceId'), '/'))]" - }, - "storageAccount": { - "condition": "[not(empty(parameters('storageAccountResourceId')))]", - "existing": true, - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2023-05-01", - "subscriptionId": "[split(parameters('storageAccountResourceId'), '/')[2]]", - "resourceGroup": "[split(parameters('storageAccountResourceId'), '/')[4]]", - "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" - }, - "slotSettings": { - "type": "Microsoft.Web/sites/slots/config", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'appsettings')]", - "kind": "[parameters('kind')]", - "properties": "[union(coalesce(parameters('currentAppSettings'), createObject()), coalesce(parameters('appSettingsKeyValuePairs'), createObject()), if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('storageAccountUseIdentityAuthentication'))), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', last(split(parameters('storageAccountResourceId'), '/')), listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('storageAccountResourceId'), '/')[2], split(parameters('storageAccountResourceId'), '/')[4]), 'Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2023-05-01').keys[0].value, environment().suffixes.storage)), if(and(not(empty(parameters('storageAccountResourceId'))), parameters('storageAccountUseIdentityAuthentication')), union(createObject('AzureWebJobsStorage__accountName', last(split(parameters('storageAccountResourceId'), '/'))), createObject('AzureWebJobsStorage__blobServiceUri', reference('storageAccount').primaryEndpoints.blob)), createObject())), if(not(empty(parameters('appInsightResourceId'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference('appInsight').ConnectionString), createObject()))]", - "dependsOn": [ - "appInsight", - "storageAccount" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the slot config." - }, - "value": "appsettings" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the slot config." - }, - "value": "[resourceId('Microsoft.Web/sites/slots/config', parameters('appName'), parameters('slotName'), 'appsettings')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the slot config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "slot" - ] - }, - "slot_authsettingsv2": { - "condition": "[not(empty(parameters('authSettingV2Configuration')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Slot-{1}-Config-AuthSettingsV2', uniqueString(deployment().name, parameters('location')), parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "slotName": { - "value": "[parameters('name')]" - }, - "appName": { - "value": "[parameters('appName')]" - }, - "kind": { - "value": "[parameters('kind')]" - }, - "authSettingV2Configuration": { - "value": "[coalesce(parameters('authSettingV2Configuration'), createObject())]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "4602741618711602070" - }, - "name": "Site Slot Auth Settings V2 Config", - "description": "This module deploys a Site Auth Settings V2 Configuration." - }, - "parameters": { - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent site resource. Required if the template is used in a standalone deployment." - } - }, - "slotName": { - "type": "string", - "metadata": { - "description": "Required. Slot name to be configured." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "functionapp", - "functionapp,linux", - "functionapp,workflowapp", - "functionapp,workflowapp,linux", - "functionapp,linux,container", - "functionapp,linux,container,azurecontainerapps", - "app,linux", - "app", - "linux,api", - "api", - "app,linux,container", - "app,container,windows" - ], - "metadata": { - "description": "Required. Type of site to deploy." - } - }, - "authSettingV2Configuration": { - "type": "object", - "metadata": { - "description": "Required. The auth settings V2 configuration." - } - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/slots/config", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), 'authsettingsV2')]", - "kind": "[parameters('kind')]", - "properties": "[parameters('authSettingV2Configuration')]" - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the slot config." - }, - "value": "authsettingsV2" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the slot config." - }, - "value": "[resourceId('Microsoft.Web/sites/slots/config', parameters('appName'), parameters('slotName'), 'authsettingsV2')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the slot config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "slot" - ] - }, - "slot_basicPublishingCredentialsPolicies": { - "copy": { - "name": "slot_basicPublishingCredentialsPolicies", - "count": "[length(coalesce(parameters('basicPublishingCredentialsPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Slot-Publish-Cred-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appName": { - "value": "[parameters('appName')]" - }, - "slotName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('basicPublishingCredentialsPolicies'), createArray())[copyIndex()].name]" - }, - "allow": { - "value": "[tryGet(coalesce(parameters('basicPublishingCredentialsPolicies'), createArray())[copyIndex()], 'allow')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "8803130402255189673" - }, - "name": "Web Site Slot Basic Publishing Credentials Policies", - "description": "This module deploys a Web Site Slot Basic Publishing Credentials Policy." - }, - "parameters": { - "name": { - "type": "string", - "allowedValues": [ - "scm", - "ftp" - ], - "metadata": { - "description": "Required. The name of the resource." - } - }, - "allow": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Set to true to enable or false to disable a publishing method." - } - }, - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent web site. Required if the template is used in a standalone deployment." - } - }, - "slotName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent web site slot. Required if the template is used in a standalone deployment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}/{2}', parameters('appName'), parameters('slotName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "allow": "[parameters('allow')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the basic publishing credential policy." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the basic publishing credential policy." - }, - "value": "[resourceId('Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies', parameters('appName'), parameters('slotName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the basic publishing credential policy was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Web/sites/slots/basicPublishingCredentialsPolicies', parameters('appName'), parameters('slotName'), parameters('name')), '2024-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "slot" - ] - }, - "slot_hybridConnectionRelays": { - "copy": { - "name": "slot_hybridConnectionRelays", - "count": "[length(coalesce(parameters('hybridConnectionRelays'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Slot-HybridConnectionRelay-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "hybridConnectionResourceId": { - "value": "[coalesce(parameters('hybridConnectionRelays'), createArray())[copyIndex()].resourceId]" - }, - "appName": { - "value": "[parameters('appName')]" - }, - "slotName": { - "value": "[parameters('name')]" - }, - "sendKeyName": { - "value": "[tryGet(coalesce(parameters('hybridConnectionRelays'), createArray())[copyIndex()], 'sendKeyName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "16445776675656358479" - }, - "name": "Web/Function Apps Slot Hybrid Connection Relay", - "description": "This module deploys a Site Slot Hybrid Connection Namespace Relay." - }, - "parameters": { - "hybridConnectionResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the relay namespace hybrid connection." - } - }, - "slotName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the site slot. Required if the template is used in a standalone deployment." - } - }, - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent web site. Required if the template is used in a standalone deployment." - } - }, - "sendKeyName": { - "type": "string", - "defaultValue": "defaultSender", - "metadata": { - "description": "Optional. Name of the authorization rule send key to use." - } - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/slots/hybridConnectionNamespaces/relays", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}/{2}/{3}', parameters('appName'), parameters('slotName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10])]", - "properties": { - "serviceBusNamespace": "[split(parameters('hybridConnectionResourceId'), '/')[8]]", - "serviceBusSuffix": "[split(substring(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces', split(parameters('hybridConnectionResourceId'), '/')[8]), '2021-11-01').serviceBusEndpoint, indexOf(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces', split(parameters('hybridConnectionResourceId'), '/')[8]), '2021-11-01').serviceBusEndpoint, '.servicebus')), ':')[0]]", - "relayName": "[split(parameters('hybridConnectionResourceId'), '/')[10]]", - "relayArmUri": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10])]", - "hostname": "[split(json(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '2021-11-01').userMetadata)[0].value, ':')[0]]", - "port": "[int(split(json(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '2021-11-01').userMetadata)[0].value, ':')[1])]", - "sendKeyName": "[parameters('sendKeyName')]", - "sendKeyValue": "[listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections/authorizationRules', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10], parameters('sendKeyName')), '2021-11-01').primaryKey]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the hybrid connection relay.." - }, - "value": "[format('{0}/{1}/{2}/{3}', parameters('appName'), parameters('slotName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10])]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the hybrid connection relay." - }, - "value": "[resourceId('Microsoft.Web/sites/slots/hybridConnectionNamespaces/relays', split(format('{0}/{1}/{2}/{3}', parameters('appName'), parameters('slotName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '/')[0], split(format('{0}/{1}/{2}/{3}', parameters('appName'), parameters('slotName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '/')[1], split(format('{0}/{1}/{2}/{3}', parameters('appName'), parameters('slotName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '/')[2], split(format('{0}/{1}/{2}/{3}', parameters('appName'), parameters('slotName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '/')[3])]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the resource was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "slot" - ] - }, - "slot_extensionMSdeploy": { - "condition": "[not(empty(parameters('msDeployConfiguration')))]", - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Site-Extension-MSDeploy', uniqueString(deployment().name, parameters('location')))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "appName": { - "value": "[parameters('appName')]" - }, - "msDeployConfiguration": { - "value": "[coalesce(parameters('msDeployConfiguration'), createObject())]" - } - }, - "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.33.93.31351", - "templateHash": "14895622660217616811" - }, - "name": "Site Deployment Extension ", - "description": "This module deploys a Site extension for MSDeploy." - }, - "parameters": { - "appName": { - "type": "string", - "metadata": { - "description": "Required. The name of the parent site resource." - } - }, - "msDeployConfiguration": { - "type": "object", - "nullable": true, - "metadata": { - "description": "Optional. Sets the MSDeployment Properties." - } - } - }, - "resources": { - "app": { - "existing": true, - "type": "Microsoft.Web/sites", - "apiVersion": "2024-04-01", - "name": "[parameters('appName')]" - }, - "msdeploy": { - "type": "Microsoft.Web/sites/extensions", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('appName'), 'MSDeploy')]", - "kind": "MSDeploy", - "properties": "[parameters('msDeployConfiguration')]" - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the MSDeploy Package." - }, - "value": "MSDeploy" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the Site Extension." - }, - "value": "[resourceId('Microsoft.Web/sites/extensions', parameters('appName'), 'MSDeploy')]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the site config was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - } - }, - "slot_privateEndpoints": { - "copy": { - "name": "slot_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-slot-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('appName')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name'))), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('appName')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), format('sites-{0}', parameters('name')))), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.13.18514", - "templateHash": "15954548978129725136" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "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.5.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": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "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." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.10.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(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": "2022-09-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.33.13.18514", - "templateHash": "5440815542537978381" - }, - "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 - } - } - }, - "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." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-11-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-11-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "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": [ - "slot" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the slot." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the slot." - }, - "value": "[resourceId('Microsoft.Web/sites/slots', parameters('appName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the slot was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('slot', '2024-04-01', 'full'), 'identity'), 'principalId')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('slot', '2024-04-01', 'full').location]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the slot." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('slot_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('slot_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('slot_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('slot_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('slot_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - } - } - } - }, - "dependsOn": [ - "app" - ] - }, - "app_basicPublishingCredentialsPolicies": { - "copy": { - "name": "app_basicPublishingCredentialsPolicies", - "count": "[length(coalesce(parameters('basicPublishingCredentialsPolicies'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-Site-Publish-Cred-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "webAppName": { - "value": "[parameters('name')]" - }, - "name": { - "value": "[coalesce(parameters('basicPublishingCredentialsPolicies'), createArray())[copyIndex()].name]" - }, - "allow": { - "value": "[tryGet(coalesce(parameters('basicPublishingCredentialsPolicies'), createArray())[copyIndex()], 'allow')]" - }, - "location": { - "value": "[parameters('location')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "7001118912896436334" - }, - "name": "Web Site Basic Publishing Credentials Policies", - "description": "This module deploys a Web Site Basic Publishing Credentials Policy." - }, - "parameters": { - "name": { - "type": "string", - "allowedValues": [ - "scm", - "ftp" - ], - "metadata": { - "description": "Required. The name of the resource." - } - }, - "allow": { - "type": "bool", - "defaultValue": true, - "metadata": { - "description": "Optional. Set to true to enable or false to disable a publishing method." - } - }, - "webAppName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent web site. Required if the template is used in a standalone deployment." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. Location for all Resources." - } - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/basicPublishingCredentialsPolicies", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}', parameters('webAppName'), parameters('name'))]", - "location": "[parameters('location')]", - "properties": { - "allow": "[parameters('allow')]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the basic publishing credential policy." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the basic publishing credential policy." - }, - "value": "[resourceId('Microsoft.Web/sites/basicPublishingCredentialsPolicies', parameters('webAppName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the basic publishing credential policy was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference(resourceId('Microsoft.Web/sites/basicPublishingCredentialsPolicies', parameters('webAppName'), parameters('name')), '2024-04-01', 'full').location]" - } - } - } - }, - "dependsOn": [ - "app" - ] - }, - "app_hybridConnectionRelays": { - "copy": { - "name": "app_hybridConnectionRelays", - "count": "[length(coalesce(parameters('hybridConnectionRelays'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-01", - "name": "[format('{0}-HybridConnectionRelay-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "hybridConnectionResourceId": { - "value": "[coalesce(parameters('hybridConnectionRelays'), createArray())[copyIndex()].resourceId]" - }, - "appName": { - "value": "[parameters('name')]" - }, - "sendKeyName": { - "value": "[tryGet(coalesce(parameters('hybridConnectionRelays'), createArray())[copyIndex()], 'sendKeyName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.93.31351", - "templateHash": "13214417392638890300" - }, - "name": "Web/Function Apps Hybrid Connection Relay", - "description": "This module deploys a Site Hybrid Connection Namespace Relay." - }, - "parameters": { - "hybridConnectionResourceId": { - "type": "string", - "metadata": { - "description": "Required. The resource ID of the relay namespace hybrid connection." - } - }, - "appName": { - "type": "string", - "metadata": { - "description": "Conditional. The name of the parent web site. Required if the template is used in a standalone deployment." - } - }, - "sendKeyName": { - "type": "string", - "defaultValue": "defaultSender", - "metadata": { - "description": "Optional. Name of the authorization rule send key to use." - } - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/hybridConnectionNamespaces/relays", - "apiVersion": "2024-04-01", - "name": "[format('{0}/{1}/{2}', parameters('appName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10])]", - "properties": { - "serviceBusNamespace": "[split(parameters('hybridConnectionResourceId'), '/')[8]]", - "serviceBusSuffix": "[split(substring(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces', split(parameters('hybridConnectionResourceId'), '/')[8]), '2021-11-01').serviceBusEndpoint, indexOf(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces', split(parameters('hybridConnectionResourceId'), '/')[8]), '2021-11-01').serviceBusEndpoint, '.servicebus')), ':')[0]]", - "relayName": "[split(parameters('hybridConnectionResourceId'), '/')[10]]", - "relayArmUri": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10])]", - "hostname": "[split(json(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '2021-11-01').userMetadata)[0].value, ':')[0]]", - "port": "[int(split(json(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '2021-11-01').userMetadata)[0].value, ':')[1])]", - "sendKeyName": "[parameters('sendKeyName')]", - "sendKeyValue": "[listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('hybridConnectionResourceId'), '/')[2], split(parameters('hybridConnectionResourceId'), '/')[4]), 'Microsoft.Relay/namespaces/hybridConnections/authorizationRules', split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10], parameters('sendKeyName')), '2021-11-01').primaryKey]" - } - } - ], - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the hybrid connection relay.." - }, - "value": "[format('{0}/{1}/{2}', parameters('appName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10])]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the hybrid connection relay." - }, - "value": "[resourceId('Microsoft.Web/sites/hybridConnectionNamespaces/relays', split(format('{0}/{1}/{2}', parameters('appName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '/')[0], split(format('{0}/{1}/{2}', parameters('appName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '/')[1], split(format('{0}/{1}/{2}', parameters('appName'), split(parameters('hybridConnectionResourceId'), '/')[8], split(parameters('hybridConnectionResourceId'), '/')[10]), '/')[2])]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The name of the resource group the resource was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "app" - ] - }, - "app_privateEndpoints": { - "copy": { - "name": "app_privateEndpoints", - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" - }, - "type": "Microsoft.Resources/deployments", - "apiVersion": "2022-09-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]]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex()))]" - }, - "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites')))))), createObject('value', null()))]", - "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.Web/sites', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Web/sites', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'sites')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", - "subnetResourceId": { - "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" - }, - "enableTelemetry": { - "value": "[variables('enableReferencedModulesTelemetry')]" - }, - "location": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" - }, - "lock": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" - }, - "privateDnsZoneGroup": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" - }, - "roleAssignments": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" - }, - "tags": { - "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" - }, - "customDnsConfigs": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" - }, - "ipConfigurations": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" - }, - "applicationSecurityGroupResourceIds": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" - }, - "customNetworkInterfaceName": { - "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "languageVersion": "2.0", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.33.13.18514", - "templateHash": "15954548978129725136" - }, - "name": "Private Endpoints", - "description": "This module deploys a Private Endpoint." - }, - "definitions": { - "privateDnsZoneGroupType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The name of the Private DNS Zone Group." - } - }, - "privateDnsZoneGroupConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/privateDnsZoneGroupConfigType" - }, - "metadata": { - "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "ipConfigurationType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the resource that is unique within a resource group." - } - }, - "properties": { - "type": "object", - "properties": { - "groupId": { - "type": "string", - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "memberName": { - "type": "string", - "metadata": { - "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." - } - }, - "privateIPAddress": { - "type": "string", - "metadata": { - "description": "Required. A private IP address obtained from the private endpoint's subnet." - } - } - }, - "metadata": { - "description": "Required. Properties of private endpoint IP configurations." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "privateLinkServiceConnectionType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "metadata": { - "description": "Required. The name of the private link service connection." - } - }, - "properties": { - "type": "object", - "properties": { - "groupIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." - } - }, - "privateLinkServiceId": { - "type": "string", - "metadata": { - "description": "Required. The resource id of private link service." - } - }, - "requestMessage": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." - } - } - }, - "metadata": { - "description": "Required. Properties of private link service connection." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "customDnsConfigType": { - "type": "object", - "properties": { - "fqdn": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. FQDN that resolves to private endpoint IP address." - } - }, - "ipAddresses": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "Required. A list of private IP addresses of the private endpoint." - } - } - }, - "metadata": { - "__bicep_export!": true - } - }, - "lockType": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. Specify the name of lock." - } - }, - "kind": { - "type": "string", - "allowedValues": [ - "CanNotDelete", - "None", - "ReadOnly" - ], - "nullable": true, - "metadata": { - "description": "Optional. Specify the type of lock." - } - } - }, - "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.5.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": { - "__bicep_imported_from!": { - "sourceTemplate": "private-dns-zone-group/main.bicep" - } - } - }, - "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.5.1" - } - } - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Required. Name of the private endpoint resource to create." - } - }, - "subnetResourceId": { - "type": "string", - "metadata": { - "description": "Required. Resource ID of the subnet where the endpoint needs to be created." - } - }, - "applicationSecurityGroupResourceIds": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. Application security groups in which the private endpoint IP configuration is included." - } - }, - "customNetworkInterfaceName": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The custom name of the network interface attached to the private endpoint." - } - }, - "ipConfigurations": { - "type": "array", - "items": { - "$ref": "#/definitions/ipConfigurationType" - }, - "nullable": true, - "metadata": { - "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." - } - }, - "privateDnsZoneGroup": { - "$ref": "#/definitions/privateDnsZoneGroupType", - "nullable": true, - "metadata": { - "description": "Optional. The private DNS zone group to configure for the private endpoint." - } - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "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", - "nullable": true, - "metadata": { - "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." - } - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "nullable": true, - "metadata": { - "description": "Optional. Custom DNS configurations." - } - }, - "manualPrivateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "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." - } - }, - "privateLinkServiceConnections": { - "type": "array", - "items": { - "$ref": "#/definitions/privateLinkServiceConnectionType" - }, - "nullable": true, - "metadata": { - "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." - } - }, - "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": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.10.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", - "properties": { - "mode": "Incremental", - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "resources": [], - "outputs": { - "telemetry": { - "type": "String", - "value": "For more information, see https://aka.ms/avm/TelemetryInfo" - } - } - } - } - }, - "privateEndpoint": { - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-11-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "copy": [ - { - "name": "applicationSecurityGroups", - "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", - "input": { - "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" - } - } - ], - "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", - "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", - "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", - "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", - "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", - "subnet": { - "id": "[parameters('subnetResourceId')]" - } - } - }, - "privateEndpoint_lock": { - "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", - "type": "Microsoft.Authorization/locks", - "apiVersion": "2020-05-01", - "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", - "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", - "properties": { - "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", - "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" - }, - "dependsOn": [ - "privateEndpoint" - ] - }, - "privateEndpoint_roleAssignments": { - "copy": { - "name": "privateEndpoint_roleAssignments", - "count": "[length(coalesce(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": "2022-09-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.33.13.18514", - "templateHash": "5440815542537978381" - }, - "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 - } - } - }, - "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." - } - } - }, - "variables": { - "copy": [ - { - "name": "privateDnsZoneConfigsVar", - "count": "[length(parameters('privateDnsZoneConfigs'))]", - "input": { - "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", - "properties": { - "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" - } - } - } - ] - }, - "resources": { - "privateEndpoint": { - "existing": true, - "type": "Microsoft.Network/privateEndpoints", - "apiVersion": "2023-11-01", - "name": "[parameters('privateEndpointName')]" - }, - "privateDnsZoneGroup": { - "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", - "apiVersion": "2023-11-01", - "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", - "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" - } - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint DNS zone group." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint DNS zone group." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint DNS zone group was deployed into." - }, - "value": "[resourceGroup().name]" - } - } - } - }, - "dependsOn": [ - "privateEndpoint" - ] - } - }, - "outputs": { - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the private endpoint was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the private endpoint." - }, - "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" - }, - "name": { - "type": "string", - "metadata": { - "description": "The name of the private endpoint." - }, - "value": "[parameters('name')]" - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" - }, - "customDnsConfigs": { - "type": "array", - "items": { - "$ref": "#/definitions/customDnsConfigType" - }, - "metadata": { - "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": [ - "app" - ] - } - }, - "outputs": { - "name": { - "type": "string", - "metadata": { - "description": "The name of the site." - }, - "value": "[parameters('name')]" - }, - "resourceId": { - "type": "string", - "metadata": { - "description": "The resource ID of the site." - }, - "value": "[resourceId('Microsoft.Web/sites', parameters('name'))]" - }, - "slots": { - "type": "array", - "metadata": { - "description": "The list of the slots." - }, - "copy": { - "count": "[length(coalesce(parameters('slots'), createArray()))]", - "input": "[format('{0}-Slot-{1}', uniqueString(deployment().name, parameters('location')), coalesce(parameters('slots'), createArray())[copyIndex()].name)]" - } - }, - "slotResourceIds": { - "type": "array", - "metadata": { - "description": "The list of the slot resource ids." - }, - "copy": { - "count": "[length(coalesce(parameters('slots'), createArray()))]", - "input": "[reference(format('app_slots[{0}]', copyIndex())).outputs.resourceId.value]" - } - }, - "resourceGroupName": { - "type": "string", - "metadata": { - "description": "The resource group the site was deployed into." - }, - "value": "[resourceGroup().name]" - }, - "systemAssignedMIPrincipalId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "The principal ID of the system assigned identity." - }, - "value": "[tryGet(tryGet(reference('app', '2024-04-01', 'full'), 'identity'), 'principalId')]" - }, - "slotSystemAssignedMIPrincipalIds": { - "type": "array", - "items": { - "type": "string" - }, - "metadata": { - "description": "The principal ID of the system assigned identity of slots." - }, - "copy": { - "count": "[length(coalesce(parameters('slots'), createArray()))]", - "input": "[coalesce(tryGet(tryGet(reference(format('app_slots[{0}]', copyIndex())).outputs, 'systemAssignedMIPrincipalId'), 'value'), '')]" - } - }, - "location": { - "type": "string", - "metadata": { - "description": "The location the resource was deployed into." - }, - "value": "[reference('app', '2024-04-01', 'full').location]" - }, - "defaultHostname": { - "type": "string", - "metadata": { - "description": "Default hostname of the app." - }, - "value": "[reference('app').defaultHostName]" - }, - "customDomainVerificationId": { - "type": "string", - "metadata": { - "description": "Unique identifier that verifies the custom domains assigned to the app. Customer will add this ID to a txt record for verification." - }, - "value": "[reference('app').customDomainVerificationId]" - }, - "privateEndpoints": { - "type": "array", - "items": { - "$ref": "#/definitions/privateEndpointOutputType" - }, - "metadata": { - "description": "The private endpoints of the site." - }, - "copy": { - "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", - "input": { - "name": "[reference(format('app_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", - "resourceId": "[reference(format('app_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", - "groupId": "[tryGet(tryGet(reference(format('app_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", - "customDnsConfigs": "[reference(format('app_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", - "networkInterfaceResourceIds": "[reference(format('app_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" - } - } - }, - "slotPrivateEndpoints": { - "type": "array", - "metadata": { - "description": "The private endpoints of the slots." - }, - "copy": { - "count": "[length(coalesce(parameters('slots'), createArray()))]", - "input": "[reference(format('app_slots[{0}]', copyIndex())).outputs.privateEndpoints.value]" - } - }, - "outboundIpAddresses": { - "type": "string", - "metadata": { - "description": "The outbound IP addresses of the app." - }, - "value": "[reference('app').outboundIpAddresses]" - } - } - } - }, - "dependsOn": [ - "applicationInsights", - "containerApp", - "logAnalyticsWorkspace", - "webServerFarm" - ] - } - }, - "outputs": { - "webSiteDefaultHostname": { - "type": "string", - "metadata": { - "description": "The default url of the website to connect to the Multi-Agent Custom Automation Engine solution." - }, - "value": "[reference('webSite').outputs.defaultHostname.value]" - }, - "COSMOSDB_ENDPOINT": { - "type": "string", - "value": "[format('https://{0}.documents.azure.com:443/', variables('cosmosDbResourceName'))]" - }, - "COSMOSDB_DATABASE": { - "type": "string", - "value": "[variables('cosmosDbDatabaseName')]" - }, - "COSMOSDB_CONTAINER": { - "type": "string", - "value": "[variables('cosmosDbDatabaseMemoryContainerName')]" - }, - "AZURE_OPENAI_ENDPOINT": { - "type": "string", - "value": "[format('https://{0}.openai.azure.com/', variables('aiFoundryAiServicesResourceName'))]" - }, - "AZURE_OPENAI_MODEL_NAME": { - "type": "string", - "value": "[variables('aiFoundryAiServicesModelDeployment').name]" - }, - "AZURE_OPENAI_DEPLOYMENT_NAME": { - "type": "string", - "value": "[variables('aiFoundryAiServicesModelDeployment').name]" - }, - "AZURE_OPENAI_API_VERSION": { - "type": "string", - "value": "[parameters('azureopenaiVersion')]" - }, - "AZURE_AI_SUBSCRIPTION_ID": { - "type": "string", - "value": "[subscription().subscriptionId]" - }, - "AZURE_AI_RESOURCE_GROUP": { - "type": "string", - "value": "[resourceGroup().name]" - }, - "AZURE_AI_PROJECT_NAME": { - "type": "string", - "value": "[variables('aiFoundryAiProjectName')]" - }, - "AZURE_AI_MODEL_DEPLOYMENT_NAME": { - "type": "string", - "value": "[variables('aiFoundryAiServicesModelDeployment').name]" - }, - "AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME": { - "type": "string", - "value": "[variables('aiFoundryAiServicesModelDeployment').name]" - }, - "AZURE_AI_AGENT_ENDPOINT": { - "type": "string", - "value": "[reference('aiFoundryAiServices').outputs.aiProjectInfo.value.apiEndpoint]" - }, - "APP_ENV": { - "type": "string", - "value": "Prod" - }, - "AI_FOUNDRY_RESOURCE_ID": { - "type": "string", - "value": "[reference('aiFoundryAiServices').outputs.resourceId.value]" - }, - "COSMOSDB_ACCOUNT_NAME": { - "type": "string", - "value": "[variables('cosmosDbResourceName')]" - } - } -} \ No newline at end of file diff --git a/infra/main.parameters.json b/infra/main.parameters.json index 16b465617..14965085a 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -1,102 +1,42 @@ { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "aiModelDeployments": { - "value": [ - { - "name": "gpt", - "model": { - "name": "gpt-4o", - "version": "2024-08-06", - "format": "OpenAI" - }, - "sku": { - "name": "GlobalStandard", - "capacity": 140 - } - } - ] - }, - "environmentName": { - "value": "${AZURE_ENV_NAME}" - }, - "solutionLocation": { - "value": "${AZURE_LOCATION}" - }, - "aiDeploymentsLocation": { - "value": "${AZURE_ENV_OPENAI_LOCATION}" - }, - "modelDeploymentType": { - "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" - }, - "gptModelName": { - "value": "${AZURE_ENV_MODEL_NAME}" - }, - "gptModelVersion": { - "value": "${AZURE_ENV_MODEL_VERSION}" - }, - "gptModelCapacity": { - "value": "${AZURE_ENV_MODEL_CAPACITY}" - }, - "existingFoundryProjectResourceId": { - "value": "${AZURE_ENV_FOUNDRY_PROJECT_ID}" - }, - "imageTag": { - "value": "${AZURE_ENV_IMAGE_TAG}" - }, - "enableTelemetry": { - "value": "${AZURE_ENV_ENABLE_TELEMETRY}" - }, - "existingLogAnalyticsWorkspaceId": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "solutionName": { + "value": "${AZURE_ENV_NAME}" + }, + "location": { + "value": "${AZURE_LOCATION}" + }, + "azureAiServiceLocation": { + "value": "${AZURE_ENV_OPENAI_LOCATION}" + }, + "gptModelDeploymentType": { + "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" + }, + "gptModelName": { + "value": "${AZURE_ENV_MODEL_NAME}" + }, + "gptModelVersion": { + "value": "${AZURE_ENV_MODEL_VERSION}" + }, + "gptModelCapacity": { + "value": "${AZURE_ENV_MODEL_CAPACITY}" + }, + "backendContainerImageTag": { + "value": "${AZURE_ENV_IMAGE_TAG=latest}" + }, + "frontendContainerImageTag": { + "value": "${AZURE_ENV_IMAGE_TAG=latest}" + }, + "enableTelemetry": { + "value": "${AZURE_ENV_ENABLE_TELEMETRY}" + }, + "existingLogAnalyticsWorkspaceId": { "value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}" - }, - "backendExists": { - "value": "${SERVICE_BACKEND_RESOURCE_EXISTS=false}" - }, - "backendDefinition": { - "value": { - "settings": [ - { - "name": "", - "value": "${VAR}", - "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", - "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR} to use the value of 'VAR' from the current environment." - }, - { - "name": "", - "value": "${VAR_S}", - "secret": true, - "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", - "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR_S} to use the value of 'VAR_S' from the current environment." - } - ] - } - }, - "frontendExists": { - "value": "${SERVICE_FRONTEND_RESOURCE_EXISTS=false}" - }, - "frontendDefinition": { - "value": { - "settings": [ - { - "name": "", - "value": "${VAR}", - "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", - "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR} to use the value of 'VAR' from the current environment." - }, - { - "name": "", - "value": "${VAR_S}", - "secret": true, - "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", - "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR_S} to use the value of 'VAR_S' from the current environment." - } - ] - } - }, - "principalId": { - "value": "${AZURE_PRINCIPAL_ID}" - } + }, + "existingAiFoundryAiProjectResourceId": { + "value": "${AZURE_ENV_FOUNDRY_PROJECT_ID}" } + } } \ No newline at end of file diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json new file mode 100644 index 000000000..c6fd16c49 --- /dev/null +++ b/infra/main.waf.parameters.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "solutionName": { + "value": "${AZURE_ENV_NAME}" + }, + "location": { + "value": "${AZURE_LOCATION}" + }, + "azureAiServiceLocation": { + "value": "${AZURE_ENV_OPENAI_LOCATION}" + }, + "gptModelDeploymentType": { + "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" + }, + "gptModelName": { + "value": "${AZURE_ENV_MODEL_NAME}" + }, + "gptModelVersion": { + "value": "${AZURE_ENV_MODEL_VERSION}" + }, + "gptModelCapacity": { + "value": "${AZURE_ENV_MODEL_CAPACITY}" + }, + "backendContainerImageTag": { + "value": "${AZURE_ENV_IMAGE_TAG=latest}" + }, + "frontendContainerImageTag": { + "value": "${AZURE_ENV_IMAGE_TAG=latest}" + }, + "enableTelemetry": { + "value": "${AZURE_ENV_ENABLE_TELEMETRY}" + }, + "enableMonitoring": { + "value": true + }, + "enablePrivateNetworking": { + "value": true + }, + "enableScalability": { + "value": true + }, + "virtualMachineAdminUsername": { + "value": "${AZURE_ENV_VM_ADMIN_USERNAME}" + }, + "virtualMachineAdminPassword": { + "value": "${AZURE_ENV_VM_ADMIN_PASSWORD}" + }, + "existingLogAnalyticsWorkspaceId": { + "value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}" + }, + "existingAiFoundryAiProjectResourceId": { + "value": "${AZURE_ENV_FOUNDRY_PROJECT_ID}" + } + } +} \ No newline at end of file diff --git a/infra/main_custom.bicep b/infra/main_custom.bicep index 8eb51293f..25542deb3 100644 --- a/infra/main_custom.bicep +++ b/infra/main_custom.bicep @@ -1,309 +1,359 @@ -metadata name = 'Multi-Agent Custom Automation Engine' -metadata description = 'This module contains the resources required to deploy the Multi-Agent Custom Automation Engine solution accelerator for both Sandbox environments and WAF aligned environments.' - -@description('Set to true if you want to deploy WAF-aligned infrastructure.') -param useWafAlignedArchitecture bool - -@description('Use this parameter to use an existing AI project resource ID') -param existingFoundryProjectResourceId string = '' - -@description('Required. Name of the environment to deploy the solution into.') -param environmentName string - -@description('Required. Location for all Resources except AI Foundry.') -param solutionLocation string = resourceGroup().location - -@description('Optional. Enable/Disable usage telemetry for module.') -param enableTelemetry bool = true +// // ========== main_custom.bicep ========== // +targetScope = 'resourceGroup' -param existingLogAnalyticsWorkspaceId string = '' - -param azureopenaiVersion string = '2025-01-01-preview' +metadata name = 'Multi-Agent Custom Automation Engine' +metadata description = '''This module contains the resources required to deploy the [Multi-Agent Custom Automation Engine solution accelerator](https://github.com/microsoft/Multi-Agent-Custom-Automation-Engine-Solution-Accelerator) for both Sandbox environments and WAF aligned environments. + +> **Note:** This module is not intended for broad, generic use, as it was designed by the Commercial Solution Areas CTO team, as a Microsoft Solution Accelerator. Feature requests and bug fix requests are welcome if they support the needs of this organization but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. This module will likely be updated to leverage AVM resource modules in the future. This may result in breaking changes in upcoming versions when these features are implemented. +''' + +@description('Optional. A unique application/solution name for all resources in this deployment. This should be 3-16 characters long.') +@minLength(3) +@maxLength(16) +param solutionName string = 'macae' + +@maxLength(5) +@description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') +param solutionUniqueText string = take(uniqueString(subscription().id, resourceGroup().name, solutionName), 5) + +@metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for all services. 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/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).') +@allowed([ + 'australiaeast' + 'centralus' + 'eastasia' + 'eastus' + 'eastus2' + 'japaneast' + 'northeurope' + 'southeastasia' + 'westeurope' + 'uksouth' +]) +param location string //Get the current deployer's information var deployerInfo = deployer() var deployingUserPrincipalId = deployerInfo.objectId // Restricting deployment to only supported Azure OpenAI regions validated with GPT-4o model +@allowed(['australiaeast', 'eastus2', 'francecentral', 'japaneast', 'norwayeast', 'swedencentral', 'uksouth', 'westus']) @metadata({ - azd : { + azd: { type: 'location' - usageName : [ - 'OpenAI.GlobalStandard.gpt-4o, 150' + usageName: [ + 'OpenAI.GlobalStandard.o4-mini, 50' + 'OpenAI.GlobalStandard.gpt4.1-mini, 50' ] } }) -@allowed(['australiaeast', 'eastus2', 'francecentral', 'japaneast', 'norwayeast', 'swedencentral', 'uksouth', 'westus']) -@description('Azure OpenAI Location') -param aiDeploymentsLocation string +@description('Required. Location for all AI service resources. This should be one of the supported Azure AI Service locations.') +param azureAiServiceLocation string + +@minLength(1) +@description('Optional. Name of the GPT model to deploy:') +param gptModelName string = 'gpt-4.1-mini' + +@description('Optional. Version of the GPT model to deploy. Defaults to 2025-04-14.') +param gptModelVersion string = '2025-04-14' @minLength(1) -@description('Name of the GPT model to deploy:') -param gptModelName string = 'gpt-4o' +@description('Optional. Name of the GPT Reasoning model to deploy:') +param gptReasoningModelName string = 'o4-mini' -param gptModelVersion string = '2024-08-06' +@description('Optional. Version of the GPT Reasoning model to deploy. Defaults to 2025-04-14.') +param gptReasoningModelVersion string = '2025-04-16' + +@description('Optional. Version of the Azure OpenAI service to deploy. Defaults to 2025-01-01-preview.') +param azureopenaiVersion string = '2024-12-01-preview' @minLength(1) -@description('GPT model deployment type:') -param modelDeploymentType string = 'GlobalStandard' +@allowed([ + 'Standard' + 'GlobalStandard' +]) +@description('Optional. GPT model deployment type. Defaults to GlobalStandard.') +param gptModelDeploymentType string = 'GlobalStandard' -@description('Optional. AI model deployment token capacity.') -param gptModelCapacity int = 150 +@minLength(1) +@allowed([ + 'Standard' + 'GlobalStandard' +]) +@description('Optional. GPT model deployment type. Defaults to GlobalStandard.') +param gptReasoningModelDeploymentType string = 'GlobalStandard' -@description('Set the image tag for the container images used in the solution. Default is "latest".') -param imageTag string = 'latest' +@description('Optional. AI model deployment token capacity. Defaults to 150 for optimal performance.') +param gptModelCapacity int = 50 -param solutionPrefix string = 'macae-${padLeft(take(toLower(uniqueString(subscription().id, environmentName, resourceGroup().location, resourceGroup().name)), 12), 12, '0')}' +@description('Optional. AI model deployment token capacity. Defaults to 150 for optimal performance.') +param gptReasoningModelCapacity int = 50 @description('Optional. The tags to apply to all deployed Azure resources.') -param tags object = { - app: solutionPrefix - location: solutionLocation -} +param tags resourceInput<'Microsoft.Resources/resourceGroups@2025-04-01'>.tags = {} -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource.') -param logAnalyticsWorkspaceConfiguration logAnalyticsWorkspaceConfigurationType = { - enabled: true - name: 'log-${solutionPrefix}' - location: solutionLocation - sku: 'PerGB2018' - tags: tags - dataRetentionInDays: useWafAlignedArchitecture ? 365 : 30 - existingWorkspaceResourceId: existingLogAnalyticsWorkspaceId -} +@description('Optional. Enable monitoring applicable resources, aligned with the Well Architected Framework recommendations. This setting enables Application Insights and Log Analytics and configures all the resources applicable resources to send logs. Defaults to false.') +param enableMonitoring bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Application Insights resource.') -param applicationInsightsConfiguration applicationInsightsConfigurationType = { - enabled: true - name: 'appi-${solutionPrefix}' - location: solutionLocation - tags: tags - retentionInDays: useWafAlignedArchitecture ? 365 : 30 -} +@description('Optional. Enable scalability for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableScalability bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Managed Identity resource.') -param userAssignedManagedIdentityConfiguration userAssignedManagedIdentityType = { - enabled: true - name: 'id-${solutionPrefix}' - location: solutionLocation - tags: tags -} +@description('Optional. Enable redundancy for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enableRedundancy bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the backend subnet.') -param networkSecurityGroupBackendConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-backend-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@description('Optional. Enable private networking for applicable resources, aligned with the Well Architected Framework recommendations. Defaults to false.') +param enablePrivateNetworking bool = false -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the containers subnet.') -param networkSecurityGroupContainersConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-containers-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@secure() +@description('Optional. The user name for the administrator account of the virtual machine. Allows to customize credentials if `enablePrivateNetworking` is set to true.') +param virtualMachineAdminUsername string = take(newGuid(), 20) -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the Bastion subnet.') -param networkSecurityGroupBastionConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-bastion-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@description('Optional. The password for the administrator account of the virtual machine. Allows to customize credentials if `enablePrivateNetworking` is set to true.') +@secure() +param virtualMachineAdminPassword string = newGuid() -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the administration subnet.') -param networkSecurityGroupAdministrationConfiguration networkSecurityGroupConfigurationType = { - enabled: true - name: 'nsg-administration-${solutionPrefix}' - location: solutionLocation - tags: tags - securityRules: null //Default value set on module configuration -} +@description('Optional. The Container Registry hostname where the docker images for the backend are located.') +param backendContainerRegistryHostname string = 'biabcontainerreg.azurecr.io' -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine virtual network resource.') -param virtualNetworkConfiguration virtualNetworkConfigurationType = { - enabled: useWafAlignedArchitecture ? true : false - name: 'vnet-${solutionPrefix}' - location: solutionLocation - tags: tags - addressPrefixes: null //Default value set on module configuration - subnets: null //Default value set on module configuration -} +@description('Optional. The Container Image Name to deploy on the backend.') +param backendContainerImageName string = 'macaebackend' -@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine bastion resource.') -param bastionConfiguration bastionConfigurationType = { - enabled: true - name: 'bas-${solutionPrefix}' - location: solutionLocation - tags: tags - sku: 'Standard' - virtualNetworkResourceId: null //Default value set on module configuration - publicIpResourceName: 'pip-bas${solutionPrefix}' -} +@description('Optional. The Container Image Tag to deploy on the backend.') +param backendContainerImageTag string = 'latest_2025-07-22_895' -@description('Optional. Configuration for the Windows virtual machine.') -param virtualMachineConfiguration virtualMachineConfigurationType = { - enabled: true - name: 'vm${solutionPrefix}' - location: solutionLocation - tags: tags - adminUsername: 'adminuser' - adminPassword: useWafAlignedArchitecture? 'P@ssw0rd1234' : guid(solutionPrefix, subscription().subscriptionId) - vmSize: 'Standard_D2s_v3' - subnetResourceId: null //Default value set on module configuration -} +@description('Optional. The Container Registry hostname where the docker images for the frontend are located.') +param frontendContainerRegistryHostname string = 'biabcontainerreg.azurecr.io' -@description('Optional. The configuration to apply for the AI Foundry AI Services resource.') -param aiFoundryAiServicesConfiguration aiServicesConfigurationType = { - enabled: true - name: 'aisa-${solutionPrefix}' - location: aiDeploymentsLocation - sku: 'S0' - deployments: null //Default value set on module configuration - subnetResourceId: null //Default value set on module configuration - modelCapacity: gptModelCapacity -} +@description('Optional. The Container Image Name to deploy on the frontend.') +param frontendContainerImageName string = 'macaefrontend' -@description('Optional. The configuration to apply for the AI Foundry AI Project resource.') -param aiFoundryAiProjectConfiguration aiProjectConfigurationType = { - enabled: true - name: 'aifp-${solutionPrefix}' - location: aiDeploymentsLocation - sku: 'Basic' - tags: tags -} +@description('Optional. The Container Image Tag to deploy on the frontend.') +param frontendContainerImageTag string = 'latest_2025-07-22_895' -@description('Optional. The configuration to apply for the Cosmos DB Account resource.') -param cosmosDbAccountConfiguration cosmosDbAccountConfigurationType = { - enabled: true - name: 'cosmos-${solutionPrefix}' - location: solutionLocation - tags: tags - subnetResourceId: null //Default value set on module configuration - sqlDatabases: null //Default value set on module configuration -} +@description('Optional. The Container Registry hostname where the docker images for the MCP are located.') +param MCPContainerRegistryHostname string = 'macaemcpacrdk.azurecr.io' -@description('Optional. The configuration to apply for the Container App Environment resource.') -param containerAppEnvironmentConfiguration containerAppEnvironmentConfigurationType = { - enabled: true - name: 'cae-${solutionPrefix}' - location: solutionLocation - tags: tags - subnetResourceId: null //Default value set on module configuration -} +@description('Optional. The Container Image Name to deploy on the MCP.') +param MCPContainerImageName string = 'macae-mac-app' -@description('Optional. The configuration to apply for the Container App resource.') -param containerAppConfiguration containerAppConfigurationType = { - enabled: true - name: 'ca-${solutionPrefix}' - location: solutionLocation - tags: union(tags, { 'azd-service-name': 'backend' }) - environmentResourceId: null //Default value set on module configuration - concurrentRequests: '100' - containerCpu: '2.0' - containerMemory: '4.0Gi' - containerImageRegistryDomain: '' - containerImageName: 'macaebackend' - containerImageTag: imageTag - containerName: 'backend' - ingressTargetPort: 8000 - maxReplicas: 1 - minReplicas: 1 -} +@description('Optional. The Container Image Tag to deploy on the MCP.') +param MCPContainerImageTag string = 't9' -@description('Optional. The configuration to apply for the Web Server Farm resource.') -param webServerFarmConfiguration webServerFarmConfigurationType = { - enabled: true - name: 'asp-${solutionPrefix}' - location: solutionLocation - skuName: useWafAlignedArchitecture? 'P1v3' : 'B2' - skuCapacity: useWafAlignedArchitecture ? 3 : 1 - tags: tags -} +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Resource ID of an existing Log Analytics Workspace.') +param existingLogAnalyticsWorkspaceId string = '' -@description('Optional. The configuration to apply for the Web Server Farm resource.') -param webSiteConfiguration webSiteConfigurationType = { - enabled: true - name: 'app-${solutionPrefix}' - location: solutionLocation - containerImageRegistryDomain: 'biabcontainerreg.azurecr.io' - containerImageName: 'macaefrontend' - containerImageTag: imageTag - containerName: 'backend' - tags: union(tags, { 'azd-service-name': 'frontend' }) - environmentResourceId: null //Default value set on module configuration +@description('Optional. Resource ID of an existing Ai Foundry AI Services resource.') +param existingAiFoundryAiProjectResourceId string = '' + +// ============== // +// Variables // +// ============== // + +var solutionSuffix = toLower(trim(replace( + replace( + replace(replace(replace(replace('${solutionName}${solutionUniqueText}', '-', ''), '_', ''), '.', ''), '/', ''), + ' ', + '' + ), + '*', + '' +))) + +// 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' + centralus: 'eastus2' + eastasia: 'southeastasia' + eastus: 'centralus' + eastus2: 'centralus' + japaneast: 'australiaeast' + northeurope: 'westeurope' + southeastasia: 'eastasia' + uksouth: 'westeurope' + westeurope: 'northeurope' +} +// Paired location calculated based on 'location' parameter. This location will be used by applicable resources if `enableScalability` is set to `true` +var cosmosDbHaLocation = cosmosDbZoneRedundantHaRegionPairs[location] + +// Replica regions list based on article in [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Enhance resilience by replicating your Log Analytics workspace across regions](https://learn.microsoft.com/azure/azure-monitor/logs/workspace-replication#supported-regions) for supported regions for Log Analytics Workspace. +var replicaRegionPairs = { + australiaeast: 'australiasoutheast' + centralus: 'westus' + eastasia: 'japaneast' + eastus: 'centralus' + eastus2: 'centralus' + japaneast: 'eastasia' + northeurope: 'westeurope' + southeastasia: 'eastasia' + uksouth: 'westeurope' + westeurope: 'northeurope' } +var replicaLocation = replicaRegionPairs[location] + +// ============== // +// Resources // +// ============== // + +var allTags = union( + { + 'azd-env-name': solutionName + }, + tags +) +@description('Optional created by user name') +param createdBy string = empty(deployer().userPrincipalName) ? '' : split(deployer().userPrincipalName, '@')[0] -// ========== Resource Group Tag ========== // resource resourceGroupTags 'Microsoft.Resources/tags@2021-04-01' = { name: 'default' properties: { tags: { - ...tags - TemplateName: 'Macae' + ...allTags + TemplateName: 'MACAE' + CreatedBy: createdBy + } + } +} + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.sa-multiagentcustauteng.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } } } } +// Extracts subscription, resource group, and workspace name from the resource ID when using an existing Log Analytics workspace +var useExistingLogAnalytics = !empty(existingLogAnalyticsWorkspaceId) + +var existingLawSubscription = useExistingLogAnalytics ? split(existingLogAnalyticsWorkspaceId, '/')[2] : '' +var existingLawResourceGroup = useExistingLogAnalytics ? split(existingLogAnalyticsWorkspaceId, '/')[4] : '' +var existingLawName = useExistingLogAnalytics ? split(existingLogAnalyticsWorkspaceId, '/')[8] : '' + +resource existingLogAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2020-08-01' existing = if (useExistingLogAnalytics) { + name: existingLawName + scope: resourceGroup(existingLawSubscription, existingLawResourceGroup) +} + // ========== Log Analytics Workspace ========== // // WAF best practices for Log Analytics: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-log-analytics -// Log Analytics configuration defaults -var logAnalyticsWorkspaceEnabled = logAnalyticsWorkspaceConfiguration.?enabled ?? true -var logAnalyticsWorkspaceResourceName = logAnalyticsWorkspaceConfiguration.?name ?? 'log-${solutionPrefix}' -var existingWorkspaceResourceId = logAnalyticsWorkspaceConfiguration.?existingWorkspaceResourceId ?? '' -var useExistingWorkspace = existingWorkspaceResourceId != '' - -module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.11.2' = if (logAnalyticsWorkspaceEnabled && !useExistingWorkspace) { +// WAF PSRules for Log Analytics: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#azure-monitor-logs +var logAnalyticsWorkspaceResourceName = 'log-${solutionSuffix}' +module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.12.0' = if (enableMonitoring && !useExistingLogAnalytics) { name: take('avm.res.operational-insights.workspace.${logAnalyticsWorkspaceResourceName}', 64) params: { name: logAnalyticsWorkspaceResourceName - tags: logAnalyticsWorkspaceConfiguration.?tags ?? tags - location: logAnalyticsWorkspaceConfiguration.?location ?? solutionLocation + tags: tags + location: location enableTelemetry: enableTelemetry - skuName: logAnalyticsWorkspaceConfiguration.?sku ?? 'PerGB2018' - dataRetention: logAnalyticsWorkspaceConfiguration.?dataRetentionInDays ?? 365 + skuName: 'PerGB2018' + dataRetention: 365 + features: { enableLogAccessUsingOnlyResourcePermissions: true } diagnosticSettings: [{ useThisWorkspace: true }] + // WAF aligned configuration for Redundancy + dailyQuotaGb: enableRedundancy ? 10 : null //WAF recommendation: 10 GB per day is a good starting point for most workloads + replication: enableRedundancy + ? { + enabled: true + location: replicaLocation + } + : null + // WAF aligned configuration for Private Networking + publicNetworkAccessForIngestion: enablePrivateNetworking ? 'Disabled' : 'Enabled' + publicNetworkAccessForQuery: enablePrivateNetworking ? 'Disabled' : 'Enabled' + dataSources: enablePrivateNetworking + ? [ + { + tags: tags + eventLogName: 'Application' + eventTypes: [ + { + eventType: 'Error' + } + { + eventType: 'Warning' + } + { + eventType: 'Information' + } + ] + kind: 'WindowsEvent' + name: 'applicationEvent' + } + { + counterName: '% Processor Time' + instanceName: '*' + intervalSeconds: 60 + kind: 'WindowsPerformanceCounter' + name: 'windowsPerfCounter1' + objectName: 'Processor' + } + { + kind: 'IISLogs' + name: 'sampleIISLog1' + state: 'OnPremiseEnabled' + } + ] + : null } } - -var logAnalyticsWorkspaceId = useExistingWorkspace ? existingWorkspaceResourceId : logAnalyticsWorkspace.outputs.resourceId +// Log Analytics Name, workspace ID, customer ID, and shared key (existing or new) +var logAnalyticsWorkspaceName = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.name + : logAnalyticsWorkspace!.outputs.name +var logAnalyticsWorkspaceResourceId = useExistingLogAnalytics + ? existingLogAnalyticsWorkspaceId + : logAnalyticsWorkspace!.outputs.resourceId +var logAnalyticsPrimarySharedKey = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.listKeys().primarySharedKey + : logAnalyticsWorkspace!.outputs!.primarySharedKey +var logAnalyticsWorkspaceId = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.properties.customerId + : logAnalyticsWorkspace!.outputs.logAnalyticsWorkspaceId // ========== Application Insights ========== // // WAF best practices for Application Insights: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/application-insights -// Application Insights configuration defaults -var applicationInsightsEnabled = applicationInsightsConfiguration.?enabled ?? true -var applicationInsightsResourceName = applicationInsightsConfiguration.?name ?? 'appi-${solutionPrefix}' -module applicationInsights 'br/public:avm/res/insights/component:0.6.0' = if (applicationInsightsEnabled) { +// WAF PSRules for Application Insights: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#application-insights +var applicationInsightsResourceName = 'appi-${solutionSuffix}' +module applicationInsights 'br/public:avm/res/insights/component:0.6.0' = if (enableMonitoring) { name: take('avm.res.insights.component.${applicationInsightsResourceName}', 64) params: { name: applicationInsightsResourceName - workspaceResourceId: logAnalyticsWorkspaceId - location: applicationInsightsConfiguration.?location ?? solutionLocation + tags: tags + location: location enableTelemetry: enableTelemetry - tags: applicationInsightsConfiguration.?tags ?? tags - retentionInDays: applicationInsightsConfiguration.?retentionInDays ?? 365 - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + retentionInDays: 365 kind: 'web' disableIpMasking: false flowType: 'Bluefield' + // WAF aligned configuration for Monitoring + workspaceResourceId: enableMonitoring ? logAnalyticsWorkspaceResourceId : '' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null } } -// ========== User assigned identity Web Site ========== // +// ========== User Assigned Identity ========== // // WAF best practices for identity and access management: https://learn.microsoft.com/en-us/azure/well-architected/security/identity-access -var userAssignedManagedIdentityEnabled = userAssignedManagedIdentityConfiguration.?enabled ?? true -var userAssignedManagedIdentityResourceName = userAssignedManagedIdentityConfiguration.?name ?? 'id-${solutionPrefix}' -module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.1' = if (userAssignedManagedIdentityEnabled) { - name: take('avm.res.managed-identity.user-assigned-identity.${userAssignedManagedIdentityResourceName}', 64) +var userAssignedIdentityResourceName = 'id-${solutionSuffix}' +module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.1' = { + name: take('avm.res.managed-identity.user-assigned-identity.${userAssignedIdentityResourceName}', 64) params: { - name: userAssignedManagedIdentityResourceName - tags: userAssignedManagedIdentityConfiguration.?tags ?? tags - location: userAssignedManagedIdentityConfiguration.?location ?? solutionLocation + name: userAssignedIdentityResourceName + location: location + tags: tags enableTelemetry: enableTelemetry } } @@ -311,79 +361,46 @@ module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-id // ========== Network Security Groups ========== // // WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network // WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking -var networkSecurityGroupBackendEnabled = networkSecurityGroupBackendConfiguration.?enabled ?? true -var networkSecurityGroupBackendResourceName = networkSecurityGroupBackendConfiguration.?name ?? 'nsg-backend-${solutionPrefix}' -module networkSecurityGroupBackend 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupBackendEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupBackendResourceName}', 64) +var networkSecurityGroupBackendResourceName = 'nsg-${solutionSuffix}-backend' +module networkSecurityGroupBackend 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.backend.${networkSecurityGroupBackendResourceName}', 64) params: { name: networkSecurityGroupBackendResourceName - location: networkSecurityGroupBackendConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupBackendConfiguration.?tags ?? tags - enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupBackendConfiguration.?securityRules ?? [ - // { - // name: 'DenySshRdpOutbound' //Azure Bastion - // properties: { - // priority: 200 - // access: 'Deny' - // protocol: '*' - // direction: 'Outbound' - // sourceAddressPrefix: 'VirtualNetwork' - // sourcePortRange: '*' - // destinationAddressPrefix: '*' - // destinationPortRanges: [ - // '3389' - // '22' - // ] - // } - // } - ] - } -} - -var networkSecurityGroupContainersEnabled = networkSecurityGroupContainersConfiguration.?enabled ?? true -var networkSecurityGroupContainersResourceName = networkSecurityGroupContainersConfiguration.?name ?? 'nsg-containers-${solutionPrefix}' -module networkSecurityGroupContainers 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupContainersEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupContainersResourceName}', 64) - params: { - name: networkSecurityGroupContainersResourceName - location: networkSecurityGroupContainersConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupContainersConfiguration.?tags ?? tags + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupContainersConfiguration.?securityRules ?? [ - // { - // name: 'DenySshRdpOutbound' //Azure Bastion - // properties: { - // priority: 200 - // access: 'Deny' - // protocol: '*' - // direction: 'Outbound' - // sourceAddressPrefix: 'VirtualNetwork' - // sourcePortRange: '*' - // destinationAddressPrefix: '*' - // destinationPortRanges: [ - // '3389' - // '22' - // ] - // } - // } + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } ] } } -var networkSecurityGroupBastionEnabled = networkSecurityGroupBastionConfiguration.?enabled ?? true -var networkSecurityGroupBastionResourceName = networkSecurityGroupBastionConfiguration.?name ?? 'nsg-bastion-${solutionPrefix}' -module networkSecurityGroupBastion 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupBastionEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupBastionResourceName}', 64) +var networkSecurityGroupBastionResourceName = 'nsg-${solutionSuffix}-bastion' +module networkSecurityGroupBastion 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.bastion${networkSecurityGroupBastionResourceName}', 64) params: { name: networkSecurityGroupBastionResourceName - location: networkSecurityGroupBastionConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupBastionConfiguration.?tags ?? tags + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupBastionConfiguration.?securityRules ?? [ + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ { name: 'AllowHttpsInBound' properties: { @@ -530,33 +547,92 @@ module networkSecurityGroupBastion 'br/public:avm/res/network/network-security-g } } -var networkSecurityGroupAdministrationEnabled = networkSecurityGroupAdministrationConfiguration.?enabled ?? true -var networkSecurityGroupAdministrationResourceName = networkSecurityGroupAdministrationConfiguration.?name ?? 'nsg-administration-${solutionPrefix}' -module networkSecurityGroupAdministration 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupAdministrationEnabled) { - name: take('avm.res.network.network-security-group.${networkSecurityGroupAdministrationResourceName}', 64) +var networkSecurityGroupAdministrationResourceName = 'nsg-${solutionSuffix}-administration' +module networkSecurityGroupAdministration 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.administration.${networkSecurityGroupAdministrationResourceName}', 64) params: { name: networkSecurityGroupAdministrationResourceName - location: networkSecurityGroupAdministrationConfiguration.?location ?? solutionLocation - tags: networkSecurityGroupAdministrationConfiguration.?tags ?? tags + location: location + tags: tags + enableTelemetry: enableTelemetry + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } +} + +var networkSecurityGroupContainersResourceName = 'nsg-${solutionSuffix}-containers' +module networkSecurityGroupContainers 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.containers.${networkSecurityGroupContainersResourceName}', 64) + params: { + name: networkSecurityGroupContainersResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } + ] + } +} + +var networkSecurityGroupWebsiteResourceName = 'nsg-${solutionSuffix}-website' +module networkSecurityGroupWebsite 'br/public:avm/res/network/network-security-group:0.5.1' = if (enablePrivateNetworking) { + name: take('avm.res.network.network-security-group.website.${networkSecurityGroupWebsiteResourceName}', 64) + params: { + name: networkSecurityGroupWebsiteResourceName + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - securityRules: networkSecurityGroupAdministrationConfiguration.?securityRules ?? [ - // { - // name: 'DenySshRdpOutbound' //Azure Bastion - // properties: { - // priority: 200 - // access: 'Deny' - // protocol: '*' - // direction: 'Outbound' - // sourceAddressPrefix: 'VirtualNetwork' - // sourcePortRange: '*' - // destinationAddressPrefix: '*' - // destinationPortRanges: [ - // '3389' - // '22' - // ] - // } - // } + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + securityRules: [ + { + name: 'deny-hop-outbound' + properties: { + access: 'Deny' + destinationAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + direction: 'Outbound' + priority: 200 + protocol: 'Tcp' + sourceAddressPrefix: 'VirtualNetwork' + sourcePortRange: '*' + } + } ] } } @@ -564,34 +640,35 @@ module networkSecurityGroupAdministration 'br/public:avm/res/network/network-sec // ========== Virtual Network ========== // // WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network // WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking -var virtualNetworkEnabled = virtualNetworkConfiguration.?enabled ?? true -var virtualNetworkResourceName = virtualNetworkConfiguration.?name ?? 'vnet-${solutionPrefix}' -module virtualNetwork 'br/public:avm/res/network/virtual-network:0.6.1' = if (virtualNetworkEnabled) { +var virtualNetworkResourceName = 'vnet-${solutionSuffix}' +module virtualNetwork 'br/public:avm/res/network/virtual-network:0.7.0' = if (enablePrivateNetworking) { name: take('avm.res.network.virtual-network.${virtualNetworkResourceName}', 64) params: { name: virtualNetworkResourceName - location: virtualNetworkConfiguration.?location ?? solutionLocation - tags: virtualNetworkConfiguration.?tags ?? tags + location: location + tags: tags enableTelemetry: enableTelemetry - addressPrefixes: virtualNetworkConfiguration.?addressPrefixes ?? ['10.0.0.0/8'] - subnets: virtualNetworkConfiguration.?subnets ?? [ + addressPrefixes: ['10.0.0.0/8'] + subnets: [ { name: 'backend' addressPrefix: '10.0.0.0/27' //defaultOutboundAccess: false TODO: check this configuration for a more restricted outbound access - networkSecurityGroupResourceId: networkSecurityGroupBackend.outputs.resourceId + networkSecurityGroupResourceId: networkSecurityGroupBackend!.outputs.resourceId } { name: 'administration' addressPrefix: '10.0.0.32/27' - networkSecurityGroupResourceId: networkSecurityGroupAdministration.outputs.resourceId + networkSecurityGroupResourceId: networkSecurityGroupAdministration!.outputs.resourceId + //defaultOutboundAccess: false TODO: check this configuration for a more restricted outbound access + //natGatewayResourceId: natGateway.outputs.resourceId } { // For Azure Bastion resources deployed on or after November 2, 2021, the minimum AzureBastionSubnet size is /26 or larger (/25, /24, etc.). // https://learn.microsoft.com/en-us/azure/bastion/configuration-settings#subnet name: 'AzureBastionSubnet' //This exact name is required for Azure Bastion addressPrefix: '10.0.0.64/26' - networkSecurityGroupResourceId: networkSecurityGroupBastion.outputs.resourceId + networkSecurityGroupResourceId: networkSecurityGroupBastion!.outputs.resourceId } { // If you use your own vnw, you need to provide a subnet that is dedicated exclusively to the Container App environment you deploy. This subnet isn't available to other services @@ -599,67 +676,221 @@ module virtualNetwork 'br/public:avm/res/network/virtual-network:0.6.1' = if (vi name: 'containers' addressPrefix: '10.0.2.0/23' //subnet of size /23 is required for container app delegation: 'Microsoft.App/environments' - networkSecurityGroupResourceId: networkSecurityGroupContainers.outputs.resourceId - privateEndpointNetworkPolicies: 'Disabled' + networkSecurityGroupResourceId: networkSecurityGroupContainers!.outputs.resourceId + privateEndpointNetworkPolicies: 'Enabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + { + // If you use your own vnw, you need to provide a subnet that is dedicated exclusively to the App Environment you deploy. This subnet isn't available to other services + // https://learn.microsoft.com/en-us/azure/app-service/overview-vnet-integration#subnet-requirements + name: 'webserverfarm' + addressPrefix: '10.0.4.0/27' //When you're creating subnets in Azure portal as part of integrating with the virtual network, a minimum size of /27 is required + delegation: 'Microsoft.Web/serverfarms' + networkSecurityGroupResourceId: networkSecurityGroupWebsite!.outputs.resourceId + privateEndpointNetworkPolicies: 'Enabled' privateLinkServiceNetworkPolicies: 'Enabled' } ] } } -var bastionEnabled = bastionConfiguration.?enabled ?? true -var bastionResourceName = bastionConfiguration.?name ?? 'bas-${solutionPrefix}' +var bastionResourceName = 'bas-${solutionSuffix}' // ========== Bastion host ========== // // WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network // WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking -module bastionHost 'br/public:avm/res/network/bastion-host:0.6.1' = if (virtualNetworkEnabled && bastionEnabled) { +module bastionHost 'br/public:avm/res/network/bastion-host:0.7.0' = if (enablePrivateNetworking) { name: take('avm.res.network.bastion-host.${bastionResourceName}', 64) params: { name: bastionResourceName - location: bastionConfiguration.?location ?? solutionLocation - skuName: bastionConfiguration.?sku ?? 'Standard' + location: location + skuName: 'Standard' enableTelemetry: enableTelemetry - tags: bastionConfiguration.?tags ?? tags - virtualNetworkResourceId: bastionConfiguration.?virtualNetworkResourceId ?? virtualNetwork.?outputs.?resourceId + tags: tags + virtualNetworkResourceId: virtualNetwork!.?outputs.?resourceId publicIPAddressObject: { - name: bastionConfiguration.?publicIpResourceName ?? 'pip-bas${solutionPrefix}' - zones: [] + name: 'pip-bas${solutionSuffix}' + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + tags: tags } - disableCopyPaste: false + disableCopyPaste: true enableFileCopy: false - enableIpConnect: true - enableShareableLink: true + enableIpConnect: false + enableShareableLink: false + scaleUnits: 4 + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null } } // ========== Virtual machine ========== // // WAF best practices for virtual machines: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines -var virtualMachineEnabled = virtualMachineConfiguration.?enabled ?? true -var virtualMachineResourceName = virtualMachineConfiguration.?name ?? 'vm${solutionPrefix}' -module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.13.0' = if (virtualNetworkEnabled && virtualMachineEnabled) { - name: take('avm.res.compute.virtual-machine.${virtualMachineResourceName}', 64) +var maintenanceConfigurationResourceName = 'mc-${solutionSuffix}' +module maintenanceConfiguration 'br/public:avm/res/maintenance/maintenance-configuration:0.3.1' = if (enablePrivateNetworking) { + name: take('avm.res.compute.virtual-machine.${maintenanceConfigurationResourceName}', 64) params: { - name: virtualMachineResourceName - computerName: take(virtualMachineResourceName, 15) - location: virtualMachineConfiguration.?location ?? solutionLocation - tags: virtualMachineConfiguration.?tags ?? tags + name: maintenanceConfigurationResourceName + location: location + tags: tags enableTelemetry: enableTelemetry - vmSize: virtualMachineConfiguration.?vmSize ?? 'Standard_D2s_v3' - adminUsername: virtualMachineConfiguration.?adminUsername ?? 'adminuser' - adminPassword: virtualMachineConfiguration.?adminPassword ?? guid(solutionPrefix, subscription().subscriptionId) - nicConfigurations: [ - { - name: 'nic-${virtualMachineResourceName}' - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - ipConfigurations: [ + extensionProperties: { + InGuestPatchMode: 'User' + } + maintenanceScope: 'InGuestPatch' + maintenanceWindow: { + startDateTime: '2024-06-16 00:00' + duration: '03:55' + timeZone: 'W. Europe Standard Time' + recurEvery: '1Day' + } + visibility: 'Custom' + installPatches: { + rebootSetting: 'IfRequired' + windowsParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + linuxParameters: { + classificationsToInclude: [ + 'Critical' + 'Security' + ] + } + } + } +} + +var dataCollectionRulesResourceName = 'dcr-${solutionSuffix}' +var dataCollectionRulesLocation = useExistingLogAnalytics + ? existingLogAnalyticsWorkspace!.location + : logAnalyticsWorkspace!.outputs.location +module windowsVmDataCollectionRules 'br/public:avm/res/insights/data-collection-rule:0.6.1' = if (enablePrivateNetworking && enableMonitoring) { + name: take('avm.res.insights.data-collection-rule.${dataCollectionRulesResourceName}', 64) + params: { + name: dataCollectionRulesResourceName + tags: tags + enableTelemetry: enableTelemetry + location: dataCollectionRulesLocation + dataCollectionRuleProperties: { + kind: 'Windows' + dataSources: { + performanceCounters: [ { - name: '${virtualMachineResourceName}-nic01-ipconfig01' - subnetResourceId: virtualMachineConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[1] - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + streams: [ + 'Microsoft-Perf' + ] + samplingFrequencyInSeconds: 60 + counterSpecifiers: [ + '\\Processor Information(_Total)\\% Processor Time' + '\\Processor Information(_Total)\\% Privileged Time' + '\\Processor Information(_Total)\\% User Time' + '\\Processor Information(_Total)\\Processor Frequency' + '\\System\\Processes' + '\\Process(_Total)\\Thread Count' + '\\Process(_Total)\\Handle Count' + '\\System\\System Up Time' + '\\System\\Context Switches/sec' + '\\System\\Processor Queue Length' + '\\Memory\\% Committed Bytes In Use' + '\\Memory\\Available Bytes' + '\\Memory\\Committed Bytes' + '\\Memory\\Cache Bytes' + '\\Memory\\Pool Paged Bytes' + '\\Memory\\Pool Nonpaged Bytes' + '\\Memory\\Pages/sec' + '\\Memory\\Page Faults/sec' + '\\Process(_Total)\\Working Set' + '\\Process(_Total)\\Working Set - Private' + '\\LogicalDisk(_Total)\\% Disk Time' + '\\LogicalDisk(_Total)\\% Disk Read Time' + '\\LogicalDisk(_Total)\\% Disk Write Time' + '\\LogicalDisk(_Total)\\% Idle Time' + '\\LogicalDisk(_Total)\\Disk Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Read Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Write Bytes/sec' + '\\LogicalDisk(_Total)\\Disk Transfers/sec' + '\\LogicalDisk(_Total)\\Disk Reads/sec' + '\\LogicalDisk(_Total)\\Disk Writes/sec' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Transfer' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Read' + '\\LogicalDisk(_Total)\\Avg. Disk sec/Write' + '\\LogicalDisk(_Total)\\Avg. Disk Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Read Queue Length' + '\\LogicalDisk(_Total)\\Avg. Disk Write Queue Length' + '\\LogicalDisk(_Total)\\% Free Space' + '\\LogicalDisk(_Total)\\Free Megabytes' + '\\Network Interface(*)\\Bytes Total/sec' + '\\Network Interface(*)\\Bytes Sent/sec' + '\\Network Interface(*)\\Bytes Received/sec' + '\\Network Interface(*)\\Packets/sec' + '\\Network Interface(*)\\Packets Sent/sec' + '\\Network Interface(*)\\Packets Received/sec' + '\\Network Interface(*)\\Packets Outbound Errors' + '\\Network Interface(*)\\Packets Received Errors' + ] + name: 'perfCounterDataSource60' } ] } - ] + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceResourceId + name: 'la--1264800308' + } + ] + } + dataFlows: [ + { + streams: [ + 'Microsoft-Perf' + ] + destinations: [ + 'la--1264800308' + ] + transformKql: 'source' + outputStream: 'Microsoft-Perf' + } + ] + } + } +} + +var proximityPlacementGroupResourceName = 'ppg-${solutionSuffix}' +module proximityPlacementGroup 'br/public:avm/res/compute/proximity-placement-group:0.4.0' = if (enablePrivateNetworking) { + name: take('avm.res.compute.proximity-placement-group.${proximityPlacementGroupResourceName}', 64) + params: { + name: proximityPlacementGroupResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + availabilityZone: virtualMachineAvailabilityZone + intent: { vmSizes: [virtualMachineSize] } + } +} + +var virtualMachineResourceName = 'vm-${solutionSuffix}' +var virtualMachineAvailabilityZone = 1 +var virtualMachineSize = 'Standard_D2s_v3' +module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.17.0' = if (enablePrivateNetworking) { + name: take('avm.res.compute.virtual-machine.${virtualMachineResourceName}', 64) + params: { + name: virtualMachineResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + computerName: take(virtualMachineResourceName, 15) + osType: 'Windows' + vmSize: virtualMachineSize + adminUsername: virtualMachineAdminUsername + adminPassword: virtualMachineAdminPassword + patchMode: 'AutomaticByPlatform' + bypassPlatformSafetyChecksOnUserSchedule: true + maintenanceConfigurationResourceId: maintenanceConfiguration!.outputs.resourceId + enableAutomaticUpdates: true + encryptionAtHost: false + availabilityZone: virtualMachineAvailabilityZone + proximityPlacementGroupResourceId: proximityPlacementGroup!.outputs.resourceId imageReference: { publisher: 'microsoft-dsvm' offer: 'dsvm-win-2022' @@ -668,112 +899,178 @@ module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.13.0' = if (v } osDisk: { name: 'osdisk-${virtualMachineResourceName}' + caching: 'ReadWrite' createOption: 'FromImage' - managedDisk: { - storageAccountType: 'Standard_LRS' - } + deleteOption: 'Delete' diskSizeGB: 128 - caching: 'ReadWrite' + managedDisk: { storageAccountType: 'Premium_LRS' } } - osType: 'Windows' - encryptionAtHost: false //The property 'securityProfile.encryptionAtHost' is not valid because the 'Microsoft.Compute/EncryptionAtHost' feature is not enabled for this subscription. - zone: 0 + nicConfigurations: [ + { + name: 'nic-${virtualMachineResourceName}' + //networkSecurityGroupResourceId: virtualMachineConfiguration.?nicConfigurationConfiguration.networkSecurityGroupResourceId + //nicSuffix: 'nic-${virtualMachineResourceName}' + tags: tags + deleteOption: 'Delete' + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] + : null + ipConfigurations: [ + { + name: '${virtualMachineResourceName}-nic01-ipconfig01' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[1] + diagnosticSettings: enableMonitoring //WAF aligned configuration for Monitoring + ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] + : null + } + ] + } + ] extensionAadJoinConfig: { enabled: true + tags: tags typeHandlerVersion: '1.0' } + extensionAntiMalwareConfig: { + enabled: true + settings: { + AntimalwareEnabled: 'true' + Exclusions: {} + RealtimeProtectionEnabled: 'true' + ScheduledScanSettings: { + day: '7' + isEnabled: 'true' + scanType: 'Quick' + time: '120' + } + } + tags: tags + } + //WAF aligned configuration for Monitoring + extensionMonitoringAgentConfig: enableMonitoring + ? { + dataCollectionRuleAssociations: [ + { + dataCollectionRuleResourceId: windowsVmDataCollectionRules!.outputs.resourceId + name: 'send-${logAnalyticsWorkspaceName}' + } + ] + enabled: true + tags: tags + } + : null + extensionNetworkWatcherAgentConfig: { + enabled: true + tags: tags + } } } -// ========== AI Foundry: AI Services ========== // -// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai -var openAiSubResource = 'account' -var openAiPrivateDnsZones = { - 'privatelink.cognitiveservices.azure.com': openAiSubResource - 'privatelink.openai.azure.com': openAiSubResource - 'privatelink.services.ai.azure.com': openAiSubResource +// ========== Private DNS Zones ========== // +var keyVaultPrivateDNSZone = 'privatelink.${toLower(environment().name) == 'azureusgovernment' ? 'vaultcore.usgovcloudapi.net' : 'vaultcore.azure.net'}' +var privateDnsZones = [ + 'privatelink.cognitiveservices.azure.com' + 'privatelink.openai.azure.com' + 'privatelink.services.ai.azure.com' + 'privatelink.documents.azure.com' + 'privatelink.blob.core.windows.net' + 'privatelink.search.windows.net' + keyVaultPrivateDNSZone +] + +// DNS Zone Index Constants +var dnsZoneIndex = { + cognitiveServices: 0 + openAI: 1 + aiServices: 2 + cosmosDb: 3 + blob: 4 + search: 5 + keyVault: 6 } -module privateDnsZonesAiServices 'br/public:avm/res/network/private-dns-zone:0.7.1' = [ - for zone in objectKeys(openAiPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryAIservicesEnabled) { - name: take( - 'avm.res.network.private-dns-zone.ai-services.${uniqueString(aiFoundryAiServicesResourceName,zone)}.${solutionPrefix}', - 64 - ) +// List of DNS zone indices that correspond to AI-related services. +var aiRelatedDnsZoneIndices = [ + dnsZoneIndex.cognitiveServices + dnsZoneIndex.openAI + dnsZoneIndex.aiServices +] + +// =================================================== +// DEPLOY PRIVATE DNS ZONES +// - Deploys all zones if no existing Foundry project is used +// - Excludes AI-related zones when using with an existing Foundry project +// =================================================== +@batchSize(5) +module avmPrivateDnsZones 'br/public:avm/res/network/private-dns-zone:0.7.1' = [ + for (zone, i) in privateDnsZones: if (enablePrivateNetworking && (!useExistingAiFoundryAiProject || !contains( + aiRelatedDnsZoneIndices, + i + ))) { + name: 'avm.res.network.private-dns-zone.${contains(zone, 'azurecontainerapps.io') ? 'containerappenv' : split(zone, '.')[1]}' params: { name: zone tags: tags enableTelemetry: enableTelemetry virtualNetworkLinks: [ { - name: 'vnetlink-${split(zone, '.')[1]}' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId + name: take('vnetlink-${virtualNetworkResourceName}-${split(zone, '.')[1]}', 80) + virtualNetworkResourceId: virtualNetwork!.outputs.resourceId } ] } } ] -// NOTE: Required version 'Microsoft.CognitiveServices/accounts@2024-04-01-preview' not available in AVM -var useExistingFoundryProject = !empty(existingFoundryProjectResourceId) -var existingAiFoundryName = useExistingFoundryProject?split( existingFoundryProjectResourceId,'/')[8]:'' -var aiFoundryAiServicesResourceName = useExistingFoundryProject? existingAiFoundryName : aiFoundryAiServicesConfiguration.?name ?? 'aisa-${solutionPrefix}' -var aiFoundryAIservicesEnabled = aiFoundryAiServicesConfiguration.?enabled ?? true +// ========== AI Foundry: AI Services ========== // +// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai + +var useExistingAiFoundryAiProject = !empty(existingAiFoundryAiProjectResourceId) +var aiFoundryAiServicesResourceGroupName = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[4] + : resourceGroup().name +var aiFoundryAiServicesSubscriptionId = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[2] + : subscription().subscriptionId +var aiFoundryAiServicesResourceName = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[8] + : 'aif-${solutionSuffix}' +var aiFoundryAiProjectResourceName = useExistingAiFoundryAiProject + ? split(existingAiFoundryAiProjectResourceId, '/')[10] + : 'proj-${solutionSuffix}' // AI Project resource id: /subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts//projects/ var aiFoundryAiServicesModelDeployment = { format: 'OpenAI' name: gptModelName version: gptModelVersion sku: { - name: modelDeploymentType - //Curently the capacity is set to 140 for opinanal performance. - capacity: aiFoundryAiServicesConfiguration.?modelCapacity ?? gptModelCapacity + name: gptModelDeploymentType + capacity: gptModelCapacity + } + raiPolicyName: 'Microsoft.Default' +} +var aiFoundryAiServicesReasoningModelDeployment = { + format: 'OpenAI' + name: gptReasoningModelName + version: gptReasoningModelVersion + sku: { + name: gptReasoningModelDeploymentType + capacity: gptReasoningModelCapacity } raiPolicyName: 'Microsoft.Default' } +var aiFoundryAiProjectDescription = 'AI Foundry Project' -module aiFoundryAiServices 'modules/account/main.bicep' = if (aiFoundryAIservicesEnabled) { - name: take('avm.res.cognitive-services.account.${aiFoundryAiServicesResourceName}', 64) +resource existingAiFoundryAiServices 'Microsoft.CognitiveServices/accounts@2025-06-01' existing = if (useExistingAiFoundryAiProject) { + name: aiFoundryAiServicesResourceName + scope: resourceGroup(aiFoundryAiServicesSubscriptionId, aiFoundryAiServicesResourceGroupName) +} + +module existingAiFoundryAiServicesDeployments 'modules/ai-services-deployments.bicep' = if (useExistingAiFoundryAiProject) { + name: take('module.ai-services-model-deployments.${existingAiFoundryAiServices.name}', 64) + scope: resourceGroup(aiFoundryAiServicesSubscriptionId, aiFoundryAiServicesResourceGroupName) params: { - name: aiFoundryAiServicesResourceName - tags: aiFoundryAiServicesConfiguration.?tags ?? tags - location: aiFoundryAiServicesConfiguration.?location ?? aiDeploymentsLocation - enableTelemetry: enableTelemetry - projectName: 'aifp-${solutionPrefix}' - projectDescription: 'aifp-${solutionPrefix}' - existingFoundryProjectResourceId: existingFoundryProjectResourceId - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - sku: aiFoundryAiServicesConfiguration.?sku ?? 'S0' - kind: 'AIServices' - disableLocalAuth: true //Should be set to true for WAF aligned configuration - customSubDomainName: aiFoundryAiServicesResourceName - apiProperties: { - //staticsEnabled: false - } - allowProjectManagement: true - managedIdentities: { - systemAssigned: true - } - publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' - networkAcls: { - bypass: 'AzureServices' - defaultAction: (virtualNetworkEnabled) ? 'Deny' : 'Allow' - } - privateEndpoints: virtualNetworkEnabled && !useExistingFoundryProject - ? ([ - { - name: 'pep-${aiFoundryAiServicesResourceName}' - customNetworkInterfaceName: 'nic-${aiFoundryAiServicesResourceName}' - subnetResourceId: aiFoundryAiServicesConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: map(objectKeys(openAiPrivateDnsZones), zone => { - name: replace(zone, '.', '-') - privateDnsZoneResourceId: resourceId('Microsoft.Network/privateDnsZones', zone) - }) - } - } - ]) - : [] - deployments: aiFoundryAiServicesConfiguration.?deployments ?? [ + name: existingAiFoundryAiServices.name + deployments: [ { name: aiFoundryAiServicesModelDeployment.name model: { @@ -787,115 +1084,190 @@ module aiFoundryAiServices 'modules/account/main.bicep' = if (aiFoundryAIservice capacity: aiFoundryAiServicesModelDeployment.sku.capacity } } + { + name: aiFoundryAiServicesReasoningModelDeployment.name + model: { + format: aiFoundryAiServicesReasoningModelDeployment.format + name: aiFoundryAiServicesReasoningModelDeployment.name + version: aiFoundryAiServicesReasoningModelDeployment.version + } + raiPolicyName: aiFoundryAiServicesReasoningModelDeployment.raiPolicyName + sku: { + name: aiFoundryAiServicesReasoningModelDeployment.sku.name + capacity: aiFoundryAiServicesReasoningModelDeployment.sku.capacity + } + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' // Cognitive Services OpenAI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } ] } } -// AI Foundry: AI Project -// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai -var existingAiFounryProjectName = useExistingFoundryProject ? last(split( existingFoundryProjectResourceId,'/')) : '' -var aiFoundryAiProjectName = useExistingFoundryProject ? existingAiFounryProjectName : aiFoundryAiProjectConfiguration.?name ?? 'aifp-${solutionPrefix}' - -var useExistingResourceId = !empty(existingFoundryProjectResourceId) - -module cogServiceRoleAssignmentsNew './modules/role.bicep' = if(!useExistingResourceId) { +module aiFoundryAiServices 'br:mcr.microsoft.com/bicep/avm/res/cognitive-services/account:0.13.2' = if (!useExistingAiFoundryAiProject) { + name: take('avm.res.cognitive-services.account.${aiFoundryAiServicesResourceName}', 64) params: { - name: 'new-${guid(containerApp.name, aiFoundryAiServices.outputs.resourceId)}' - principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - aiServiceName: aiFoundryAiServices.outputs.name + name: aiFoundryAiServicesResourceName + location: azureAiServiceLocation + tags: tags + sku: 'S0' + kind: 'AIServices' + disableLocalAuth: true + allowProjectManagement: true + customSubDomainName: aiFoundryAiServicesResourceName + apiProperties: { + //staticsEnabled: false + } + deployments: [ + { + name: aiFoundryAiServicesModelDeployment.name + model: { + format: aiFoundryAiServicesModelDeployment.format + name: aiFoundryAiServicesModelDeployment.name + version: aiFoundryAiServicesModelDeployment.version + } + raiPolicyName: aiFoundryAiServicesModelDeployment.raiPolicyName + sku: { + name: aiFoundryAiServicesModelDeployment.sku.name + capacity: aiFoundryAiServicesModelDeployment.sku.capacity + } + } + { + name: aiFoundryAiServicesReasoningModelDeployment.name + model: { + format: aiFoundryAiServicesReasoningModelDeployment.format + name: aiFoundryAiServicesReasoningModelDeployment.name + version: aiFoundryAiServicesReasoningModelDeployment.version + } + raiPolicyName: aiFoundryAiServicesReasoningModelDeployment.raiPolicyName + sku: { + name: aiFoundryAiServicesReasoningModelDeployment.sku.name + capacity: aiFoundryAiServicesReasoningModelDeployment.sku.capacity + } + } + ] + networkAcls: { + defaultAction: 'Allow' + virtualNetworkRules: [] + ipRules: [] + } + managedIdentities: { userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] } //To create accounts or projects, you must enable a managed identity on your resource + roleAssignments: [ + { + roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' // Cognitive Services OpenAI User + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User + principalId: deployingUserPrincipalId + principalType: 'User' + } + { + roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer + principalId: deployingUserPrincipalId + principalType: 'User' + } + ] + // WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + privateEndpoints: (enablePrivateNetworking) + ? ([ + { + name: 'pep-${aiFoundryAiServicesResourceName}' + customNetworkInterfaceName: 'nic-${aiFoundryAiServicesResourceName}' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'ai-services-dns-zone-cognitiveservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cognitiveServices]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-openai' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.openAI]!.outputs.resourceId + } + { + name: 'ai-services-dns-zone-aiservices' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.aiServices]!.outputs.resourceId + } + ] + } + } + ]) + : [] } - scope: resourceGroup(subscription().subscriptionId, resourceGroup().name) } -module cogServiceRoleAssignmentsExisting './modules/role.bicep' = if(useExistingResourceId) { - params: { - name: 'reuse-${guid(containerApp.name, aiFoundryAiServices.outputs.aiProjectInfo.resourceId)}' - principalId: containerApp.outputs.?systemAssignedMIPrincipalId! - aiServiceName: aiFoundryAiServices.outputs.name - } - scope: resourceGroup( split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4]) +resource existingAiFoundryAiServicesProject 'Microsoft.CognitiveServices/accounts/projects@2025-06-01' existing = if (useExistingAiFoundryAiProject) { + name: aiFoundryAiProjectResourceName + parent: existingAiFoundryAiServices } -// User Role Assignment for Azure OpenAI - New Resources -module userOpenAiRoleAssignment './modules/role.bicep' = if (aiFoundryAIservicesEnabled && !useExistingResourceId) { - name: take('user-openai-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}', 64) +module aiFoundryAiServicesProject 'modules/ai-project.bicep' = if (!useExistingAiFoundryAiProject) { + name: take('module.ai-project.${aiFoundryAiProjectResourceName}', 64) params: { - name: 'user-openai-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}' - principalId: deployingUserPrincipalId - aiServiceName: aiFoundryAiServices.outputs.name - principalType: 'User' + name: aiFoundryAiProjectResourceName + location: azureAiServiceLocation + tags: tags + desc: aiFoundryAiProjectDescription + //Implicit dependencies below + aiServicesName: aiFoundryAiServices!.outputs.name } - scope: resourceGroup(subscription().subscriptionId, resourceGroup().name) - dependsOn: [ - aiFoundryAiServices - ] } -// User Role Assignment for Azure OpenAI - Existing Resources -module userOpenAiRoleAssignmentExisting './modules/role.bicep' = if (aiFoundryAIservicesEnabled && useExistingResourceId) { - name: take('user-openai-existing-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}', 64) - params: { - name: 'user-openai-existing-${uniqueString(deployingUserPrincipalId, aiFoundryAiServicesResourceName)}' - principalId: deployingUserPrincipalId - aiServiceName: aiFoundryAiServices.outputs.name - principalType: 'User' - } - scope: resourceGroup(split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4]) - dependsOn: [ - aiFoundryAiServices - ] -} +var aiFoundryAiProjectName = useExistingAiFoundryAiProject + ? existingAiFoundryAiServicesProject.name + : aiFoundryAiServicesProject!.outputs.name +var aiFoundryAiProjectEndpoint = useExistingAiFoundryAiProject + ? existingAiFoundryAiServicesProject!.properties.endpoints['AI Foundry API'] + : aiFoundryAiServicesProject!.outputs.apiEndpoint +var aiFoundryAiProjectPrincipalId = useExistingAiFoundryAiProject + ? existingAiFoundryAiServicesProject!.identity.principalId + : aiFoundryAiServicesProject!.outputs.principalId // ========== Cosmos DB ========== // // WAF best practices for Cosmos DB: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/cosmos-db -module privateDnsZonesCosmosDb 'br/public:avm/res/network/private-dns-zone:0.7.0' = if (virtualNetworkEnabled) { - name: take('avm.res.network.private-dns-zone.cosmos-db.${solutionPrefix}', 64) - params: { - name: 'privatelink.documents.azure.com' - enableTelemetry: enableTelemetry - virtualNetworkLinks: [ - { - name: 'vnetlink-cosmosdb' - virtualNetworkResourceId: virtualNetwork.outputs.resourceId - } - ] - tags: tags - } -} -var cosmosDbAccountEnabled = cosmosDbAccountConfiguration.?enabled ?? true -var cosmosDbResourceName = cosmosDbAccountConfiguration.?name ?? 'cosmos-${solutionPrefix}' +var cosmosDbResourceName = 'cosmos-${solutionSuffix}' var cosmosDbDatabaseName = 'macae' var cosmosDbDatabaseMemoryContainerName = 'memory' -module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (cosmosDbAccountEnabled) { + +//TODO: update to latest version of AVM module +module cosmosDb 'br/public:avm/res/document-db/database-account:0.15.0' = { name: take('avm.res.document-db.database-account.${cosmosDbResourceName}', 64) params: { // Required parameters - name: cosmosDbAccountConfiguration.?name ?? 'cosmos-${solutionPrefix}' - location: cosmosDbAccountConfiguration.?location ?? solutionLocation - tags: cosmosDbAccountConfiguration.?tags ?? tags + name: cosmosDbResourceName + location: location + tags: tags enableTelemetry: enableTelemetry - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - databaseAccountOfferType: 'Standard' - enableFreeTier: false - networkRestrictions: { - networkAclBypass: 'None' - publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' - } - privateEndpoints: virtualNetworkEnabled - ? [ - { - name: 'pep-${cosmosDbResourceName}' - customNetworkInterfaceName: 'nic-${cosmosDbResourceName}' - privateDnsZoneGroup: { - privateDnsZoneGroupConfigs: [{ privateDnsZoneResourceId: privateDnsZonesCosmosDb.outputs.resourceId }] - } - service: 'Sql' - subnetResourceId: cosmosDbAccountConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] - } - ] - : [] - sqlDatabases: concat(cosmosDbAccountConfiguration.?sqlDatabases ?? [], [ + sqlDatabases: [ { name: cosmosDbDatabaseName containers: [ @@ -909,34 +1281,114 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (co } ] } - ]) - locations: [ - { - locationName: cosmosDbAccountConfiguration.?location ?? solutionLocation - failoverPriority: 0 - isZoneRedundant: false - } ] - capabilitiesToAdd: [ - 'EnableServerless' - ] - sqlRoleAssignmentsPrincipalIds: concat( - [containerApp.outputs.?systemAssignedMIPrincipalId], - [deployingUserPrincipalId] - ) - sqlRoleDefinitions: [ + dataPlaneRoleDefinitions: [ { - // Replace this with built-in role definition Cosmos DB Built-in Data Contributor: https://docs.azure.cn/en-us/cosmos-db/nosql/security/reference-data-plane-roles#cosmos-db-built-in-data-contributor - roleType: 'CustomRole' + // Cosmos DB Built-in Data Contributor: https://docs.azure.cn/en-us/cosmos-db/nosql/security/reference-data-plane-roles#cosmos-db-built-in-data-contributor roleName: 'Cosmos DB SQL Data Contributor' - name: 'cosmos-db-sql-data-contributor' - dataAction: [ + dataActions: [ 'Microsoft.DocumentDB/databaseAccounts/readMetadata' 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' ] + assignments: [ + { principalId: userAssignedIdentity.outputs.principalId } + { principalId: deployingUserPrincipalId } + ] } ] + // WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + // WAF aligned configuration for Private Networking + networkRestrictions: { + networkAclBypass: 'None' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + } + privateEndpoints: enablePrivateNetworking + ? [ + { + name: 'pep-${cosmosDbResourceName}' + customNetworkInterfaceName: 'nic-${cosmosDbResourceName}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.cosmosDb]!.outputs.resourceId } + ] + } + service: 'Sql' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + } + ] + : [] + // WAF aligned configuration for Redundancy + zoneRedundant: enableRedundancy ? true : false + capabilitiesToAdd: enableRedundancy ? null : ['EnableServerless'] + automaticFailover: enableRedundancy ? true : false + failoverLocations: enableRedundancy + ? [ + { + failoverPriority: 0 + isZoneRedundant: true + locationName: location + } + { + failoverPriority: 1 + isZoneRedundant: true + locationName: cosmosDbHaLocation + } + ] + : [ + { + locationName: location + failoverPriority: 0 + } + ] + } +} + +// ========== Backend Container App Environment ========== // +// WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps +// PSRule for Container App: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#container-app +var containerAppEnvironmentResourceName = 'cae-${solutionSuffix}' +module containerAppEnvironment 'br/public:avm/res/app/managed-environment:0.11.2' = { + name: take('avm.res.app.managed-environment.${containerAppEnvironmentResourceName}', 64) + params: { + name: containerAppEnvironmentResourceName + location: location + tags: tags + enableTelemetry: enableTelemetry + // WAF aligned configuration for Private Networking + publicNetworkAccess: 'Enabled' // Always enabling the publicNetworkAccess for Container App Environment + internal: false // Must be false when publicNetworkAccess is'Enabled' + infrastructureSubnetResourceId: enablePrivateNetworking ? virtualNetwork.?outputs.?subnetResourceIds[3] : null + // WAF aligned configuration for Monitoring + appLogsConfiguration: enableMonitoring + ? { + destination: 'log-analytics' + logAnalyticsConfiguration: { + customerId: logAnalyticsWorkspaceId + sharedKey: logAnalyticsPrimarySharedKey + } + } + : null + appInsightsConnectionString: enableMonitoring ? applicationInsights!.outputs.connectionString : null + // WAF aligned configuration for Redundancy + zoneRedundant: enableRedundancy ? true : false + infrastructureResourceGroupName: enableRedundancy ? '${resourceGroup().name}-infra' : null + workloadProfiles: enableRedundancy + ? [ + { + maximumCount: 3 + minimumCount: 3 + name: 'CAW01' + workloadProfileType: 'D4' + } + ] + : [ + { + name: 'Consumption' + workloadProfileType: 'Consumption' + } + ] } } @@ -944,12 +1396,12 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (co module containerRegistry 'br/public:avm/res/container-registry/registry:0.9.1' = { name: 'registryDeployment' params: { - name: 'cr${replace(solutionPrefix,'-','')}' + name: 'cr${solutionSuffix}' acrAdminUserEnabled: false acrSku: 'Basic' azureADAuthenticationAsArmPolicyStatus: 'enabled' exportPolicyStatus: 'enabled' - location: solutionLocation + location: location softDeletePolicyDays: 7 softDeletePolicyStatus: 'disabled' tags: tags @@ -966,62 +1418,38 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.9.1' = var acrPullRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') -// ========== Backend Container App Environment ========== // -// WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps -var containerAppEnvironmentEnabled = containerAppEnvironmentConfiguration.?enabled ?? true -var containerAppEnvironmentResourceName = containerAppEnvironmentConfiguration.?name ?? 'cae-${solutionPrefix}' -module containerAppEnvironment 'modules/container-app-environment.bicep' = if (containerAppEnvironmentEnabled) { - name: take('module.container-app-environment.${containerAppEnvironmentResourceName}', 64) - params: { - name: containerAppEnvironmentResourceName - tags: containerAppEnvironmentConfiguration.?tags ?? tags - location: containerAppEnvironmentConfiguration.?location ?? solutionLocation - logAnalyticsResourceId: logAnalyticsWorkspaceId - publicNetworkAccess: 'Enabled' - zoneRedundant: false - applicationInsightsConnectionString: applicationInsights.outputs.connectionString - enableTelemetry: enableTelemetry - subnetResourceId: virtualNetworkEnabled - ? containerAppEnvironmentConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[3] ?? '' - : '' - } -} - // ========== Backend Container App Service ========== // // WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps -var containerAppEnabled = containerAppConfiguration.?enabled ?? true -var containerAppResourceName = containerAppConfiguration.?name ?? 'ca-${solutionPrefix}' -module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (containerAppEnabled) { +// PSRule for Container App: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#container-app +var containerAppResourceName = 'ca-${solutionSuffix}' +module containerApp 'br/public:avm/res/app/container-app:0.18.1' = { name: take('avm.res.app.container-app.${containerAppResourceName}', 64) params: { name: containerAppResourceName - tags: containerAppConfiguration.?tags ?? tags - location: containerAppConfiguration.?location ?? solutionLocation + tags: union(tags, { 'azd-service-name': 'backend' }) + location: location enableTelemetry: enableTelemetry - environmentResourceId: containerAppConfiguration.?environmentResourceId ?? containerAppEnvironment.outputs.resourceId - managedIdentities: { - systemAssigned: true //Replace with user assigned identity - userAssignedResourceIds: [userAssignedIdentity.outputs.resourceId] - } - ingressTargetPort: containerAppConfiguration.?ingressTargetPort ?? 8000 + environmentResourceId: containerAppEnvironment.outputs.resourceId + managedIdentities: { userAssignedResourceIds: [userAssignedIdentity.outputs.resourceId] } + ingressTargetPort: 8000 ingressExternal: true activeRevisionsMode: 'Single' corsPolicy: { allowedOrigins: [ - 'https://${webSiteName}.azurewebsites.net' - 'http://${webSiteName}.azurewebsites.net' + 'https://${webSiteResourceName}.azurewebsites.net' + 'http://${webSiteResourceName}.azurewebsites.net' ] } + // WAF aligned configuration for Scalability scaleSettings: { - //TODO: Make maxReplicas and minReplicas parameterized - maxReplicas: containerAppConfiguration.?maxReplicas ?? 1 - minReplicas: containerAppConfiguration.?minReplicas ?? 1 + maxReplicas: enableScalability ? 3 : 1 + minReplicas: enableScalability ? 2 : 1 rules: [ { name: 'http-scaler' http: { metadata: { - concurrentRequests: containerAppConfiguration.?concurrentRequests ?? '100' + concurrentRequests: '100' } } } @@ -1035,13 +1463,30 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container ] containers: [ { - name: containerAppConfiguration.?containerName ?? 'backend' + name: 'backend' + //image: '${backendContainerRegistryHostname}/${backendContainerImageName}:${backendContainerImageTag}' image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' - //image: '${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}' + //TODO: configure probes for container app + // probes: [ + // { + // httpGet: { + // httpHeaders: [ + // { + // name: 'Custom-Header' + // value: 'Awesome' + // } + // ] + // path: '/health' + // port: 8080 + // } + // initialDelaySeconds: 3 + // periodSeconds: 3 + // type: 'Liveness' + // } + // ] resources: { - //TODO: Make cpu and memory parameterized - cpu: containerAppConfiguration.?containerCpu ?? '2.0' - memory: containerAppConfiguration.?containerMemory ?? '4.0Gi' + cpu: '2.0' + memory: '4.0Gi' } env: [ { @@ -1074,11 +1519,11 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container } { name: 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY' - value: applicationInsights.outputs.instrumentationKey + value: enableMonitoring ? applicationInsights!.outputs.instrumentationKey : '' } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: applicationInsights.outputs.connectionString + value: enableMonitoring ? applicationInsights!.outputs.connectionString : '' } { name: 'AZURE_AI_SUBSCRIPTION_ID' @@ -1094,11 +1539,11 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container } { name: 'FRONTEND_SITE_NAME' - value: 'https://${webSiteName}.azurewebsites.net' + value: 'https://${webSiteResourceName}.azurewebsites.net' } { name: 'AZURE_AI_AGENT_ENDPOINT' - value: aiFoundryAiServices.outputs.aiProjectInfo.apiEndpoint + value: aiFoundryAiProjectEndpoint } { name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' @@ -1108,51 +1553,125 @@ module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (container name: 'APP_ENV' value: 'Prod' } + { + name: 'AZURE_AI_SEARCH_CONNECTION_NAME' + value: searchService.outputs.name + } + { + name: 'AZURE_AI_SEARCH_INDEX_NAME' + value: aiSearchIndexName + } + { + name: 'AZURE_AI_SEARCH_ENDPOINT' + value: searchService.outputs.endpoint + } + { + name: 'AZURE_COGNITIVE_SERVICES' + value: 'https://cognitiveservices.azure.com/.default' + } + { + name: 'AZURE_BING_CONNECTION_NAME' + value: 'binggrnd' + } + { + name: 'BING_CONNECTION_NAME' + value: 'binggrnd' + } + { + name: 'REASONING_MODEL_NAME' + value: aiFoundryAiServicesReasoningModelDeployment.name + } + { + name: 'MCP_SERVER_ENDPOINT' + value: 'https://${containerAppMcp.outputs.fqdn}/mcp' + } + { + name: 'MCP_SERVER_NAME' + value: 'MACAE MCP Server' + } + { + name: 'MCP_SERVER_DESCRIPTION' + value: 'MACAE MCP Server Description' + } + { + name: 'AZURE_TENANT_ID' + value: tenant().tenantId + } + { + name: 'AZURE_CLIENT_ID' + value: userAssignedIdentity!.outputs.clientId + } + { + name: 'SUPPORTED_MODELS' + value: '["o3","o4-mini","gpt-4.1","gpt-4.1-mini"]' + } + { + name: 'AZURE_AI_SEARCH_API_KEY' + value: 'azure-ai-search-api-key' + } + { + name: 'AZURE_STORAGE_BLOB_URL' + value: avmStorageAccount.outputs.serviceEndpoints.blob + } + { + name: 'AZURE_STORAGE_CONTAINER_NAME' + value: storageContainerName + } + { + name: 'AZURE_AI_MODEL_DEPLOYMENT_NAME' + value: aiFoundryAiServicesModelDeployment.name + } ] } ] + secrets: [ + { + name: 'azure-ai-search-api-key' + keyVaultUrl: keyvault.outputs.secrets[0].uriWithVersion + identity: userAssignedIdentity.outputs.resourceId + } + ] } } - -var containerAppMcpResourceName = 'ca-mcp-${solutionPrefix}' -module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (containerAppEnabled) { +// ========== MCP Container App Service ========== // +// WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps +// PSRule for Container App: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#container-app +var containerAppMcpResourceName = 'ca-mcp-${solutionSuffix}' +module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = { name: take('avm.res.app.container-app.${containerAppMcpResourceName}', 64) params: { name: containerAppMcpResourceName tags: union(tags, { 'azd-service-name': 'mcp' }) - location: containerAppConfiguration.?location ?? solutionLocation + location: location enableTelemetry: enableTelemetry - environmentResourceId: containerAppConfiguration.?environmentResourceId ?? containerAppEnvironment.outputs.resourceId - managedIdentities: { - systemAssigned: true - userAssignedResourceIds: [userAssignedIdentity!.outputs.resourceId] - } + environmentResourceId: containerAppEnvironment.outputs.resourceId + managedIdentities: { userAssignedResourceIds: [userAssignedIdentity.outputs.resourceId] } ingressTargetPort: 9000 ingressExternal: true activeRevisionsMode: 'Single' corsPolicy: { allowedOrigins: [ - 'https://${webSiteName}.azurewebsites.net' - 'http://${webSiteName}.azurewebsites.net' + 'https://${webSiteResourceName}.azurewebsites.net' + 'http://${webSiteResourceName}.azurewebsites.net' ] } // WAF aligned configuration for Scalability scaleSettings: { - maxReplicas: containerAppConfiguration.?maxReplicas ?? 1 - minReplicas: containerAppConfiguration.?minReplicas ?? 1 + maxReplicas: enableScalability ? 3 : 1 + minReplicas: enableScalability ? 2 : 1 rules: [ { name: 'http-scaler' http: { metadata: { - concurrentRequests: containerAppConfiguration.?concurrentRequests ?? '100' + concurrentRequests: '100' } } } ] } - registries: [ + registries: [ { server: containerRegistry.outputs.loginServer identity: userAssignedIdentity.outputs.resourceId @@ -1161,11 +1680,29 @@ module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (contai containers: [ { name: 'mcp' - image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' //'${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}' + //image: '${backendContainerRegistryHostname}/${backendContainerImageName}:${backendContainerImageTag}' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + //TODO: configure probes for container app + // probes: [ + // { + // httpGet: { + // httpHeaders: [ + // { + // name: 'Custom-Header' + // value: 'Awesome' + // } + // ] + // path: '/health' + // port: 8080 + // } + // initialDelaySeconds: 3 + // periodSeconds: 3 + // type: 'Liveness' + // } + // ] resources: { - //TODO: Make cpu and memory parameterized - cpu: containerAppConfiguration.?containerCpu ?? '2.0' - memory: containerAppConfiguration.?containerMemory ?? '4.0Gi' + cpu: '2.0' + memory: '4.0Gi' } env: [ { @@ -1218,73 +1755,301 @@ module containerAppMcp 'br/public:avm/res/app/container-app:0.18.1' = if (contai } } -var webServerFarmEnabled = webServerFarmConfiguration.?enabled ?? true -var webServerFarmResourceName = webServerFarmConfiguration.?name ?? 'asp-${solutionPrefix}' - // ========== Frontend server farm ========== // -// WAF best practices for web app service: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps -module webServerFarm 'br/public:avm/res/web/serverfarm:0.4.1' = if (webServerFarmEnabled) { +// WAF best practices for Web Application Services: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps +// PSRule for Web Server Farm: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#app-service +var webServerFarmResourceName = 'asp-${solutionSuffix}' +module webServerFarm 'br/public:avm/res/web/serverfarm:0.5.0' = { name: take('avm.res.web.serverfarm.${webServerFarmResourceName}', 64) params: { name: webServerFarmResourceName tags: tags - location: webServerFarmConfiguration.?location ?? solutionLocation - skuName: webServerFarmConfiguration.?skuName ?? 'P1v3' - skuCapacity: webServerFarmConfiguration.?skuCapacity ?? 3 + enableTelemetry: enableTelemetry + location: location reserved: true - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] kind: 'linux' - zoneRedundant: false //TODO: make it zone redundant for waf aligned + // WAF aligned configuration for Monitoring + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + // WAF aligned configuration for Scalability + skuName: enableScalability || enableRedundancy ? 'P1v3' : 'B3' + skuCapacity: enableScalability ? 3 : 1 + // WAF aligned configuration for Redundancy + zoneRedundant: enableRedundancy ? true : false } } // ========== Frontend web site ========== // // WAF best practices for web app service: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps -var webSiteEnabled = webSiteConfiguration.?enabled ?? true +// PSRule for Web Server Farm: https://azure.github.io/PSRule.Rules.Azure/en/rules/resource/#app-service -var webSiteName = 'app-${solutionPrefix}' -module webSite 'br/public:avm/res/web/site:0.15.1' = if (webSiteEnabled) { - name: take('avm.res.web.site.${webSiteName}', 64) +//NOTE: AVM module adds 1 MB of overhead to the template. Keeping vanilla resource to save template size. +var webSiteResourceName = 'app-${solutionSuffix}' +module webSite 'modules/web-sites.bicep' = { + name: take('module.web-sites.${webSiteResourceName}', 64) params: { - name: webSiteName - tags: webSiteConfiguration.?tags ?? tags - location: webSiteConfiguration.?location ?? solutionLocation + name: webSiteResourceName + tags: union(tags, { 'azd-service-name': 'frontend' }) + location: location kind: 'app,linux' - //kind: 'app,linux,container' - enableTelemetry: enableTelemetry - serverFarmResourceId: webSiteConfiguration.?environmentResourceId ?? webServerFarm.?outputs.resourceId - appInsightResourceId: applicationInsights.outputs.resourceId - diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] - publicNetworkAccess: 'Enabled' //TODO: use Azure Front Door WAF or Application Gateway WAF instead + serverFarmResourceId: webServerFarm.?outputs.resourceId siteConfig: { - //linuxFxVersion: 'DOCKER|${webSiteConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${webSiteConfiguration.?containerImageName ?? 'macaefrontend'}:${webSiteConfiguration.?containerImageTag ?? 'latest'}', + //linuxFxVersion: 'DOCKER|${frontendContainerRegistryHostname}/${frontendContainerImageName}:${frontendContainerImageTag}' + minTlsVersion: '1.2' linuxFxVersion: 'python|3.11' appCommandLine: 'python3 -m uvicorn frontend_server:app --host 0.0.0.0 --port 8000' } - appSettingsKeyValuePairs: { - SCM_DO_BUILD_DURING_DEPLOYMENT: 'true' - //DOCKER_REGISTRY_SERVER_URL: 'https://${webSiteConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}' - WEBSITES_PORT: '8000' - // WEBSITES_CONTAINER_START_TIME_LIMIT: '1800' // 30 minutes, adjust as needed - BACKEND_API_URL: 'https://${containerApp.outputs.fqdn}' - AUTH_ENABLED: 'false' - APP_ENV: 'Prod' - ENABLE_ORYX_BUILD: 'True' + configs: [ + { + name: 'appsettings' + properties: { + SCM_DO_BUILD_DURING_DEPLOYMENT: 'True' + //DOCKER_REGISTRY_SERVER_URL: 'https://${frontendContainerRegistryHostname}' + WEBSITES_PORT: '8000' + //WEBSITES_CONTAINER_START_TIME_LIMIT: '1800' // 30 minutes, adjust as needed + BACKEND_API_URL: 'https://${containerApp.outputs.fqdn}' + AUTH_ENABLED: 'false' + ENABLE_ORYX_BUILD: 'True' + } + // WAF aligned configuration for Monitoring + applicationInsightResourceId: enableMonitoring ? applicationInsights!.outputs.resourceId : null + } + ] + diagnosticSettings: enableMonitoring ? [{ workspaceResourceId: logAnalyticsWorkspaceResourceId }] : null + // WAF aligned configuration for Private Networking + vnetRouteAllEnabled: enablePrivateNetworking ? true : false + vnetImagePullEnabled: enablePrivateNetworking ? true : false + virtualNetworkSubnetId: enablePrivateNetworking ? virtualNetwork!.outputs.subnetResourceIds[4] : null + publicNetworkAccess: 'Enabled' // Always enabling the public network access for Web App + } +} + + +// ========== Storage Account ========== // + +var storageAccountName = replace('st${solutionSuffix}', '-', '') +param storageContainerName string = 'sample-dataset' +module avmStorageAccount 'br/public:avm/res/storage/storage-account:0.20.0' = { + name: take('avm.res.storage.storage-account.${storageAccountName}', 64) + params: { + name: storageAccountName + location: location + managedIdentities: { systemAssigned: true } + minimumTlsVersion: 'TLS1_2' + enableTelemetry: enableTelemetry + tags: tags + accessTier: 'Hot' + supportsHttpsTrafficOnly: true + + roleAssignments: [ + { + principalId: userAssignedIdentity.outputs.principalId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: deployingUserPrincipalId + roleDefinitionIdOrName: 'Storage Blob Data Contributor' + principalType: 'User' + } + ] + + // WAF aligned networking + networkAcls: { + bypass: 'AzureServices' + defaultAction: enablePrivateNetworking ? 'Deny' : 'Allow' + } + allowBlobPublicAccess: false + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + + // Private endpoints for blob + privateEndpoints: enablePrivateNetworking + ? [ + { + name: 'pep-blob-${solutionSuffix}' + customNetworkInterfaceName: 'nic-blob-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + name: 'storage-dns-zone-group-blob' + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.blob]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + service: 'blob' + } + ] + : [] + blobServices: { + automaticSnapshotPolicyEnabled: true + containerDeleteRetentionPolicyDays: 10 + containerDeleteRetentionPolicyEnabled: true + containers: [ + { + name: storageContainerName + publicAccess: 'None' + } + ] + deleteRetentionPolicyDays: 9 + deleteRetentionPolicyEnabled: true + lastAccessTimeTrackingPolicyEnabled: true } } } +// ========== Search Service ========== // + +var searchServiceName = 'srch-${solutionSuffix}' +var aiSearchIndexName = 'sample-dataset-index' +module searchService 'br/public:avm/res/search/search-service:0.11.1' = { + name: take('avm.res.search.search-service.${solutionSuffix}', 64) + params: { + name: searchServiceName + authOptions: { + aadOrApiKey: { + aadAuthFailureMode: 'http401WithBearerChallenge' + } + } + disableLocalAuth: false + hostingMode: 'default' + managedIdentities: { + systemAssigned: true + } + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + networkRuleSet: { + bypass: 'AzureServices' + } + partitionCount: 1 + replicaCount: 1 + sku: enableScalability ? 'standard' : 'basic' + tags: tags + roleAssignments: [ + { + principalId: userAssignedIdentity.outputs.principalId + roleDefinitionIdOrName: 'Search Index Data Contributor' + principalType: 'ServicePrincipal' + } + { + principalId: deployingUserPrincipalId + roleDefinitionIdOrName: 'Search Index Data Contributor' + principalType: 'User' + } + { + principalId: aiFoundryAiProjectPrincipalId + roleDefinitionIdOrName: 'Search Index Data Reader' + principalType: 'ServicePrincipal' + } + { + principalId: aiFoundryAiProjectPrincipalId + roleDefinitionIdOrName: 'Search Service Contributor' + principalType: 'ServicePrincipal' + } + ] + privateEndpoints: enablePrivateNetworking + ? [ + { + name: 'pep-search-${solutionSuffix}' + customNetworkInterfaceName: 'nic-search-${solutionSuffix}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.search]!.outputs.resourceId + } + ] + } + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + service: 'searchService' + } + ] + : [] + } +} + +// ========== Search Service - AI Project Connection ========== // + +var aiSearchConnectionName = 'aifp-srch-connection-${solutionSuffix}' +module aiSearchFoundryConnection 'modules/aifp-connections.bicep' = { + name: take('aifp-srch-connection.${solutionSuffix}', 64) + scope: resourceGroup(aiFoundryAiServicesSubscriptionId, aiFoundryAiServicesResourceGroupName) + params: { + aiFoundryProjectName: aiFoundryAiProjectName + aiFoundryName: aiFoundryAiServicesResourceName + aifSearchConnectionName: aiSearchConnectionName + searchServiceResourceId: searchService.outputs.resourceId + searchServiceLocation: searchService.outputs.location + searchServiceName: searchService.outputs.name + searchApiKey: searchService.outputs.primaryKey + } + dependsOn: [ + aiFoundryAiServices + ] +} + + +// ========== KeyVault ========== // +var keyVaultName = 'kv-${solutionSuffix}' +module keyvault 'br/public:avm/res/key-vault/vault:0.12.1' = { + name: take('avm.res.key-vault.vault.${keyVaultName}', 64) + params: { + name: keyVaultName + location: location + tags: tags + sku: enableScalability ? 'premium' : 'standard' + publicNetworkAccess: enablePrivateNetworking ? 'Disabled' : 'Enabled' + networkAcls: { + defaultAction: 'Allow' + } + enableVaultForDeployment: true + enableVaultForDiskEncryption: true + enableVaultForTemplateDeployment: true + enableRbacAuthorization: true + enableSoftDelete: true + softDeleteRetentionInDays: 7 + diagnosticSettings: enableMonitoring + ? [{ workspaceResourceId: logAnalyticsWorkspace!.outputs.resourceId }] + : [] + // WAF aligned configuration for Private Networking + privateEndpoints: enablePrivateNetworking + ? [ + { + name: 'pep-${keyVaultName}' + customNetworkInterfaceName: 'nic-${keyVaultName}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [{ privateDnsZoneResourceId: avmPrivateDnsZones[dnsZoneIndex.keyVault]!.outputs.resourceId }] + } + service: 'vault' + subnetResourceId: virtualNetwork!.outputs.subnetResourceIds[0] + } + ] + : [] + // WAF aligned configuration for Role-based Access Control + roleAssignments: [ + { + principalId: userAssignedIdentity.outputs.principalId + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Key Vault Administrator' + } + ] + secrets: [ + { + name: 'AzureAISearchAPIKey' + value: searchService.outputs.primaryKey + } + ] + enableTelemetry: enableTelemetry + } +} + // ============ // // Outputs // // ============ // -// Add your outputs here +@description('The resource group the resources were deployed into.') +output resourceGroupName string = resourceGroup().name @description('The default url of the website to connect to the Multi-Agent Custom Automation Engine solution.') output webSiteDefaultHostname string = webSite.outputs.defaultHostname - - output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.outputs.loginServer // @description('The name of the resource.') @@ -1301,620 +2066,12 @@ output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerRegistry.outputs.logi // -@export() -@description('The type for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource configuration.') -type logAnalyticsWorkspaceConfigurationType = { - @description('Optional. If the Log Analytics Workspace resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Log Analytics Workspace resource.') - @maxLength(63) - name: string? - - @description('Optional. Location for the Log Analytics Workspace resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to for the Log Analytics Workspace resource.') - tags: object? - - @description('Optional. The SKU for the Log Analytics Workspace resource.') - sku: ('CapacityReservation' | 'Free' | 'LACluster' | 'PerGB2018' | 'PerNode' | 'Premium' | 'Standalone' | 'Standard')? - - @description('Optional. The number of days to retain the data in the Log Analytics Workspace. If empty, it will be set to 365 days.') - @maxValue(730) - dataRetentionInDays: int? - - @description('Optional: Existing Log Analytics Workspace Resource ID') - existingWorkspaceResourceId: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Application Insights resource configuration.') -type applicationInsightsConfigurationType = { - @description('Optional. If the Application Insights resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Application Insights resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Application Insights resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Application Insights resource.') - tags: object? - - @description('Optional. The retention of Application Insights data in days. If empty, Standard will be used.') - retentionInDays: (120 | 180 | 270 | 30 | 365 | 550 | 60 | 730 | 90)? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Application User Assigned Managed Identity resource configuration.') -type userAssignedManagedIdentityType = { - @description('Optional. If the User Assigned Managed Identity resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the User Assigned Managed Identity resource.') - @maxLength(128) - name: string? - - @description('Optional. Location for the User Assigned Managed Identity resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the User Assigned Managed Identity resource.') - tags: object? -} - -@export() -import { securityRuleType } from 'br/public:avm/res/network/network-security-group:0.5.1' -@description('The type for the Multi-Agent Custom Automation Engine Network Security Group resource configuration.') -type networkSecurityGroupConfigurationType = { - @description('Optional. If the Network Security Group resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Network Security Group resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Network Security Group resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Network Security Group resource.') - tags: object? - - @description('Optional. The security rules to set for the Network Security Group resource.') - securityRules: securityRuleType[]? -} - -@export() -@description('The type for the Multi-Agent Custom Automation virtual network resource configuration.') -type virtualNetworkConfigurationType = { - @description('Optional. If the Virtual Network resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Virtual Network resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Virtual Network resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Virtual Network resource.') - tags: object? - - @description('Optional. An array of 1 or more IP Addresses prefixes for the Virtual Network resource.') - addressPrefixes: string[]? - - @description('Optional. An array of 1 or more subnets for the Virtual Network resource.') - subnets: subnetType[]? -} - -import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' -type subnetType = { - @description('Optional. The Name of the subnet resource.') - name: string - - @description('Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty.') - addressPrefix: string? - - @description('Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty.') - addressPrefixes: string[]? - - @description('Optional. Application gateway IP configurations of virtual network resource.') - applicationGatewayIPConfigurations: object[]? - - @description('Optional. The delegation to enable on the subnet.') - delegation: string? - - @description('Optional. The resource ID of the NAT Gateway to use for the subnet.') - natGatewayResourceId: string? - - @description('Optional. The resource ID of the network security group to assign to the subnet.') - networkSecurityGroupResourceId: string? - - @description('Optional. enable or disable apply network policies on private endpoint in the subnet.') - privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? - - @description('Optional. enable or disable apply network policies on private link service in the subnet.') - privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? - - @description('Optional. Array of role assignments to create.') - roleAssignments: roleAssignmentType[]? - - @description('Optional. The resource ID of the route table to assign to the subnet.') - routeTableResourceId: string? - - @description('Optional. An array of service endpoint policies.') - serviceEndpointPolicies: object[]? - - @description('Optional. The service endpoints to enable on the subnet.') - serviceEndpoints: string[]? - - @description('Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet.') - defaultOutboundAccess: bool? - - @description('Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty.') - sharingScope: ('DelegatedServices' | 'Tenant')? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Bastion resource configuration.') -type bastionConfigurationType = { - @description('Optional. If the Bastion resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Bastion resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Bastion resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Bastion resource.') - tags: object? - - @description('Optional. The SKU for the Bastion resource.') - sku: ('Basic' | 'Developer' | 'Premium' | 'Standard')? - - @description('Optional. The Virtual Network resource id where the Bastion resource should be deployed.') - virtualNetworkResourceId: string? - - @description('Optional. The name of the Public Ip resource created to connect to Bastion.') - publicIpResourceName: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine virtual machine resource configuration.') -type virtualMachineConfigurationType = { - @description('Optional. If the Virtual Machine resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Virtual Machine resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the Virtual Machine resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Virtual Machine resource.') - tags: object? - - @description('Optional. Specifies the size for the Virtual Machine resource.') - vmSize: ( - | 'Basic_A0' - | 'Basic_A1' - | 'Basic_A2' - | 'Basic_A3' - | 'Basic_A4' - | 'Standard_A0' - | 'Standard_A1' - | 'Standard_A2' - | 'Standard_A3' - | 'Standard_A4' - | 'Standard_A5' - | 'Standard_A6' - | 'Standard_A7' - | 'Standard_A8' - | 'Standard_A9' - | 'Standard_A10' - | 'Standard_A11' - | 'Standard_A1_v2' - | 'Standard_A2_v2' - | 'Standard_A4_v2' - | 'Standard_A8_v2' - | 'Standard_A2m_v2' - | 'Standard_A4m_v2' - | 'Standard_A8m_v2' - | 'Standard_B1s' - | 'Standard_B1ms' - | 'Standard_B2s' - | 'Standard_B2ms' - | 'Standard_B4ms' - | 'Standard_B8ms' - | 'Standard_D1' - | 'Standard_D2' - | 'Standard_D3' - | 'Standard_D4' - | 'Standard_D11' - | 'Standard_D12' - | 'Standard_D13' - | 'Standard_D14' - | 'Standard_D1_v2' - | 'Standard_D2_v2' - | 'Standard_D3_v2' - | 'Standard_D4_v2' - | 'Standard_D5_v2' - | 'Standard_D2_v3' - | 'Standard_D4_v3' - | 'Standard_D8_v3' - | 'Standard_D16_v3' - | 'Standard_D32_v3' - | 'Standard_D64_v3' - | 'Standard_D2s_v3' - | 'Standard_D4s_v3' - | 'Standard_D8s_v3' - | 'Standard_D16s_v3' - | 'Standard_D32s_v3' - | 'Standard_D64s_v3' - | 'Standard_D11_v2' - | 'Standard_D12_v2' - | 'Standard_D13_v2' - | 'Standard_D14_v2' - | 'Standard_D15_v2' - | 'Standard_DS1' - | 'Standard_DS2' - | 'Standard_DS3' - | 'Standard_DS4' - | 'Standard_DS11' - | 'Standard_DS12' - | 'Standard_DS13' - | 'Standard_DS14' - | 'Standard_DS1_v2' - | 'Standard_DS2_v2' - | 'Standard_DS3_v2' - | 'Standard_DS4_v2' - | 'Standard_DS5_v2' - | 'Standard_DS11_v2' - | 'Standard_DS12_v2' - | 'Standard_DS13_v2' - | 'Standard_DS14_v2' - | 'Standard_DS15_v2' - | 'Standard_DS13-4_v2' - | 'Standard_DS13-2_v2' - | 'Standard_DS14-8_v2' - | 'Standard_DS14-4_v2' - | 'Standard_E2_v3' - | 'Standard_E4_v3' - | 'Standard_E8_v3' - | 'Standard_E16_v3' - | 'Standard_E32_v3' - | 'Standard_E64_v3' - | 'Standard_E2s_v3' - | 'Standard_E4s_v3' - | 'Standard_E8s_v3' - | 'Standard_E16s_v3' - | 'Standard_E32s_v3' - | 'Standard_E64s_v3' - | 'Standard_E32-16_v3' - | 'Standard_E32-8s_v3' - | 'Standard_E64-32s_v3' - | 'Standard_E64-16s_v3' - | 'Standard_F1' - | 'Standard_F2' - | 'Standard_F4' - | 'Standard_F8' - | 'Standard_F16' - | 'Standard_F1s' - | 'Standard_F2s' - | 'Standard_F4s' - | 'Standard_F8s' - | 'Standard_F16s' - | 'Standard_F2s_v2' - | 'Standard_F4s_v2' - | 'Standard_F8s_v2' - | 'Standard_F16s_v2' - | 'Standard_F32s_v2' - | 'Standard_F64s_v2' - | 'Standard_F72s_v2' - | 'Standard_G1' - | 'Standard_G2' - | 'Standard_G3' - | 'Standard_G4' - | 'Standard_G5' - | 'Standard_GS1' - | 'Standard_GS2' - | 'Standard_GS3' - | 'Standard_GS4' - | 'Standard_GS5' - | 'Standard_GS4-8' - | 'Standard_GS4-4' - | 'Standard_GS5-16' - | 'Standard_GS5-8' - | 'Standard_H8' - | 'Standard_H16' - | 'Standard_H8m' - | 'Standard_H16m' - | 'Standard_H16r' - | 'Standard_H16mr' - | 'Standard_L4s' - | 'Standard_L8s' - | 'Standard_L16s' - | 'Standard_L32s' - | 'Standard_M64s' - | 'Standard_M64ms' - | 'Standard_M128s' - | 'Standard_M128ms' - | 'Standard_M64-32ms' - | 'Standard_M64-16ms' - | 'Standard_M128-64ms' - | 'Standard_M128-32ms' - | 'Standard_NC6' - | 'Standard_NC12' - | 'Standard_NC24' - | 'Standard_NC24r' - | 'Standard_NC6s_v2' - | 'Standard_NC12s_v2' - | 'Standard_NC24s_v2' - | 'Standard_NC24rs_v2' - | 'Standard_NC6s_v3' - | 'Standard_NC12s_v3' - | 'Standard_NC24s_v3' - | 'Standard_NC24rs_v3' - | 'Standard_ND6s' - | 'Standard_ND12s' - | 'Standard_ND24s' - | 'Standard_ND24rs' - | 'Standard_NV6' - | 'Standard_NV12' - | 'Standard_NV24')? - - @description('Optional. The username for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module.') - adminUsername: string? - - @description('Optional. The password for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module.') - @secure() - adminPassword: string? - - @description('Optional. The resource ID of the subnet where the Virtual Machine resource should be deployed.') - subnetResourceId: string? -} - -@export() -import { deploymentType } from 'br/public:avm/res/cognitive-services/account:0.10.2' -@description('The type for the Multi-Agent Custom Automation Engine AI Services resource configuration.') -type aiServicesConfigurationType = { - @description('Optional. If the AI Services resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the AI Services resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the AI Services resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the AI Services resource.') - tags: object? - - @description('Optional. The SKU of the AI Services resource. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') - sku: ( - | 'C2' - | 'C3' - | 'C4' - | 'F0' - | 'F1' - | 'S' - | 'S0' - | 'S1' - | 'S10' - | 'S2' - | 'S3' - | 'S4' - | 'S5' - | 'S6' - | 'S7' - | 'S8' - | 'S9')? - - @description('Optional. The resource Id of the subnet where the AI Services private endpoint should be created.') - subnetResourceId: string? - - @description('Optional. The model deployments to set for the AI Services resource.') - deployments: deploymentType[]? - - @description('Optional. The capacity to set for AI Services GTP model.') - modelCapacity: int? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine AI Foundry AI Project resource configuration.') -type aiProjectConfigurationType = { - @description('Optional. If the AI Project resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the AI Project resource.') - @maxLength(90) - name: string? - - @description('Optional. Location for the AI Project resource deployment.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The SKU of the AI Project resource.') - sku: ('Basic' | 'Free' | 'Standard' | 'Premium')? - - @description('Optional. The tags to set for the AI Project resource.') - tags: object? -} - -import { sqlDatabaseType } from 'br/public:avm/res/document-db/database-account:0.13.0' -@export() -@description('The type for the Multi-Agent Custom Automation Engine Cosmos DB Account resource configuration.') -type cosmosDbAccountConfigurationType = { - @description('Optional. If the Cosmos DB Account resource should be deployed or not.') - enabled: bool? - @description('Optional. The name of the Cosmos DB Account resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Cosmos DB Account resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Cosmos DB Account resource.') - tags: object? - - @description('Optional. The resource Id of the subnet where the Cosmos DB Account private endpoint should be created.') - subnetResourceId: string? - - @description('Optional. The SQL databases configuration for the Cosmos DB Account resource.') - sqlDatabases: sqlDatabaseType[]? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Container App Environment resource configuration.') -type containerAppEnvironmentConfigurationType = { - @description('Optional. If the Container App Environment resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Container App Environment resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Container App Environment resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Container App Environment resource.') - tags: object? - - @description('Optional. The resource Id of the subnet where the Container App Environment private endpoint should be created.') - subnetResourceId: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Container App resource configuration.') -type containerAppConfigurationType = { - @description('Optional. If the Container App resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Container App resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Container App resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Container App resource.') - tags: object? - - @description('Optional. The resource Id of the Container App Environment where the Container App should be created.') - environmentResourceId: string? - - @description('Optional. The maximum number of replicas of the Container App.') - maxReplicas: int? - - @description('Optional. The minimum number of replicas of the Container App.') - minReplicas: int? - - @description('Optional. The ingress target port of the Container App.') - ingressTargetPort: int? - - @description('Optional. The concurrent requests allowed for the Container App.') - concurrentRequests: string? - - @description('Optional. The name given to the Container App.') - containerName: string? - - @description('Optional. The container registry domain of the container image to be used by the Container App. Default to `biabcontainerreg.azurecr.io`') - containerImageRegistryDomain: string? - - @description('Optional. The name of the container image to be used by the Container App.') - containerImageName: string? - - @description('Optional. The tag of the container image to be used by the Container App.') - containerImageTag: string? - - @description('Optional. The CPU reserved for the Container App. Defaults to 2.0') - containerCpu: string? - - @description('Optional. The Memory reserved for the Container App. Defaults to 4.0Gi') - containerMemory: string? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Entra ID Application resource configuration.') -type entraIdApplicationConfigurationType = { - @description('Optional. If the Entra ID Application for website authentication should be deployed or not.') - enabled: bool? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Web Server Farm resource configuration.') -type webServerFarmConfigurationType = { - @description('Optional. If the Web Server Farm resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Web Server Farm resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Web Server Farm resource.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Web Server Farm resource.') - tags: object? - - @description('Optional. The name of th SKU that will determine the tier, size and family for the Web Server Farm resource. This defaults to P1v3 to leverage availability zones.') - skuName: string? - - @description('Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones.') - skuCapacity: int? -} - -@export() -@description('The type for the Multi-Agent Custom Automation Engine Web Site resource configuration.') -type webSiteConfigurationType = { - @description('Optional. If the Web Site resource should be deployed or not.') - enabled: bool? - - @description('Optional. The name of the Web Site resource.') - @maxLength(60) - name: string? - - @description('Optional. Location for the Web Site resource deployment.') - @metadata({ azd: { type: 'location' } }) - location: string? - - @description('Optional. The tags to set for the Web Site resource.') - tags: object? - - @description('Optional. The resource Id of the Web Site Environment where the Web Site should be created.') - environmentResourceId: string? - - @description('Optional. The name given to the Container App.') - containerName: string? - - @description('Optional. The container registry domain of the container image to be used by the Web Site. Default to `biabcontainerreg.azurecr.io`') - containerImageRegistryDomain: string? - - @description('Optional. The name of the container image to be used by the Web Site.') - containerImageName: string? - - @description('Optional. The tag of the container image to be used by the Web Site.') - containerImageTag: string? -} - +output AZURE_STORAGE_BLOB_URL string = avmStorageAccount.outputs.serviceEndpoints.blob +output AZURE_STORAGE_ACCOUNT_NAME string = storageAccountName +output AZURE_STORAGE_CONTAINER_NAME string = storageContainerName +output AZURE_AI_SEARCH_ENDPOINT string = searchService.outputs.endpoint +output AZURE_AI_SEARCH_NAME string = searchService.outputs.name +output AZURE_AI_SEARCH_INDEX_NAME string = aiSearchIndexName output COSMOSDB_ENDPOINT string = 'https://${cosmosDbResourceName}.documents.azure.com:443/' output COSMOSDB_DATABASE string = cosmosDbDatabaseName @@ -1931,7 +2088,18 @@ output AZURE_AI_PROJECT_NAME string = aiFoundryAiProjectName output AZURE_AI_MODEL_DEPLOYMENT_NAME string = aiFoundryAiServicesModelDeployment.name // output APPLICATIONINSIGHTS_CONNECTION_STRING string = applicationInsights.outputs.connectionString output AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME string = aiFoundryAiServicesModelDeployment.name -output AZURE_AI_AGENT_ENDPOINT string = aiFoundryAiServices.outputs.aiProjectInfo.apiEndpoint +output AZURE_AI_AGENT_ENDPOINT string = aiFoundryAiProjectEndpoint output APP_ENV string = 'Prod' -output AI_FOUNDRY_RESOURCE_ID string = aiFoundryAiServices.outputs.resourceId +output AI_FOUNDRY_RESOURCE_ID string = !useExistingAiFoundryAiProject ? aiFoundryAiServices.outputs.resourceId : existingAiFoundryAiProjectResourceId output COSMOSDB_ACCOUNT_NAME string = cosmosDbResourceName +output AZURE_SEARCH_ENDPOINT string =searchService.outputs.endpoint +output AZURE_CLIENT_ID string = userAssignedIdentity!.outputs.clientId +output AZURE_TENANT_ID string = tenant().tenantId +output AZURE_AI_SEARCH_CONNECTION_NAME string = searchService.outputs.name +output AZURE_COGNITIVE_SERVICES string = 'https://cognitiveservices.azure.com/.default' +output REASONING_MODEL_NAME string = aiFoundryAiServicesReasoningModelDeployment.name +output MCP_SERVER_NAME string = 'MACAE MCP Server' +output MCP_SERVER_DESCRIPTION string = 'MACAE MCP Server Description' +output SUPPORTED_MODELS string = '["o3","o4-mini","gpt-4.1","gpt-4.1-mini"]' +output AZURE_AI_SEARCH_API_KEY string = '' +output BACKEND_URL string = 'https://${containerApp.outputs.fqdn}' diff --git a/infra/modules/ai-project.bicep b/infra/modules/ai-project.bicep new file mode 100644 index 000000000..bf4703b66 --- /dev/null +++ b/infra/modules/ai-project.bicep @@ -0,0 +1,45 @@ +@description('Required. Name of the AI Services project.') +param name string + +@description('Required. The location of the Project resource.') +param location string = resourceGroup().location + +@description('Optional. The description of the AI Foundry project to create. Defaults to the project name.') +param desc string = name + +@description('Required. Name of the existing Cognitive Services resource to create the AI Foundry project in.') +param aiServicesName string + +@description('Optional. Tags to be applied to the resources.') +param tags object = {} + +// Reference to cognitive service in current resource group for new projects +resource cogServiceReference 'Microsoft.CognitiveServices/accounts@2025-06-01' existing = { + name: aiServicesName +} + +resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-06-01' = { + parent: cogServiceReference + name: name + tags: tags + location: location + identity: { + type: 'SystemAssigned' + } + properties: { + description: desc + displayName: name + } +} + +@description('Required. Name of the AI project.') +output name string = aiProject.name + +@description('Required. Resource ID of the AI project.') +output resourceId string = aiProject.id + +@description('Required. Principal ID of the AI project managed identity.') +output principalId string = aiProject.identity.principalId + +@description('Required. API endpoint for the AI project.') +output apiEndpoint string = aiProject!.properties.endpoints['AI Foundry API'] diff --git a/infra/modules/ai-services-deployments.bicep b/infra/modules/ai-services-deployments.bicep new file mode 100644 index 000000000..8c32a0e73 --- /dev/null +++ b/infra/modules/ai-services-deployments.bicep @@ -0,0 +1,197 @@ +@description('Required. The name of Cognitive Services account.') +param name string + +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@allowed([ + 'C2' + 'C3' + 'C4' + 'F0' + 'F1' + 'S' + 'S0' + 'S1' + 'S10' + 'S2' + 'S3' + 'S4' + 'S5' + 'S6' + 'S7' + 'S8' + 'S9' +]) +param sku string = 'S0' + +import { deploymentType } from 'br:mcr.microsoft.com/bicep/avm/res/cognitive-services/account:0.13.2' +@description('Optional. Array of deployments about cognitive service accounts to create.') +param deployments deploymentType[]? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +var builtInRoleNames = { + 'Cognitive Services Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '25fbc0a9-bd7c-42a3-aa1a-3b75d497ee68' + ) + 'Cognitive Services Custom Vision Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'c1ff6cc2-c111-46fe-8896-e0ef812ad9f3' + ) + 'Cognitive Services Custom Vision Deployment': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5c4089e1-6d96-4d2f-b296-c1bc7137275f' + ) + 'Cognitive Services Custom Vision Labeler': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '88424f51-ebe7-446f-bc41-7fa16989e96c' + ) + 'Cognitive Services Custom Vision Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '93586559-c37d-4a6b-ba08-b9f0940c2d73' + ) + 'Cognitive Services Custom Vision Trainer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0a5ae4ab-0d65-4eeb-be61-29fc9b54394b' + ) + 'Cognitive Services Data Reader (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b59867f0-fa02-499b-be73-45a86b5b3e1c' + ) + 'Cognitive Services Face Recognizer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '9894cab4-e18a-44aa-828b-cb588cd6f2d7' + ) + 'Cognitive Services Immersive Reader User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b2de6794-95db-4659-8781-7e080d3f2b9d' + ) + 'Cognitive Services Language Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f07febfe-79bc-46b1-8b37-790e26e6e498' + ) + 'Cognitive Services Language Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7628b7b8-a8b2-4cdc-b46f-e9b35248918e' + ) + 'Cognitive Services Language Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2310ca1-dc64-4889-bb49-c8e0fa3d47a8' + ) + 'Cognitive Services LUIS Owner': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f72c8140-2111-481c-87ff-72b910f6e3f8' + ) + 'Cognitive Services LUIS Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18e81cdc-4e98-4e29-a639-e7d10c5a6226' + ) + 'Cognitive Services LUIS Writer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '6322a993-d5c9-4bed-b113-e49bbea25b27' + ) + 'Cognitive Services Metrics Advisor Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'cb43c632-a144-4ec5-977c-e80c4affc34a' + ) + 'Cognitive Services Metrics Advisor User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '3b20f47b-3825-43cb-8114-4bd2201156a8' + ) + 'Cognitive Services OpenAI Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a001fd3d-188f-4b5d-821b-7da978bf7442' + ) + 'Cognitive Services OpenAI User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' + ) + 'Cognitive Services QnA Maker Editor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f4cc2bf9-21be-47a1-bdf1-5c5804381025' + ) + 'Cognitive Services QnA Maker Reader': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '466ccd10-b268-4a11-b098-b4849f024126' + ) + 'Cognitive Services Speech Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '0e75ca1e-0464-4b4d-8b93-68208a576181' + ) + 'Cognitive Services Speech User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f2dc8367-1007-4938-bd23-fe263f013447' + ) + 'Cognitive Services User': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'a97b65f3-24c7-4388-baec-2e87135dc908' + ) + 'Azure AI Developer': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '64702f94-c441-49e6-a78b-ef80e0188fee' + ) + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +resource cognitiveService 'Microsoft.CognitiveServices/accounts@2025-06-01' existing = { + name: name +} + +@batchSize(1) +resource cognitiveService_deployments 'Microsoft.CognitiveServices/accounts/deployments@2024-10-01' = [ + for (deployment, index) in (deployments ?? []): { + parent: cognitiveService + name: deployment.?name ?? '${name}-deployments' + properties: { + model: deployment.model + raiPolicyName: deployment.?raiPolicyName + versionUpgradeOption: deployment.?versionUpgradeOption + } + sku: deployment.?sku ?? { + name: sku + capacity: sku.?capacity + tier: sku.?tier + size: sku.?size + family: sku.?family + } + } +] + +resource cognitiveService_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(cognitiveService.id, roleAssignment.principalId, roleAssignment.roleDefinitionId) + properties: { + roleDefinitionId: roleAssignment.roleDefinitionId + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: cognitiveService + } +] diff --git a/infra/modules/aifp_search_connection.bicep b/infra/modules/aifp-connections.bicep similarity index 85% rename from infra/modules/aifp_search_connection.bicep rename to infra/modules/aifp-connections.bicep index 3c69a8545..8afa883b3 100644 --- a/infra/modules/aifp_search_connection.bicep +++ b/infra/modules/aifp-connections.bicep @@ -4,13 +4,18 @@ param searchServiceResourceId string param searchServiceLocation string param aiFoundryName string param aiFoundryProjectName string +@secure() +param searchApiKey string resource aiSearchFoundryConnection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-04-01-preview' = { name: '${aiFoundryName}/${aiFoundryProjectName}/${aifSearchConnectionName}' properties: { category: 'CognitiveSearch' target: 'https://${searchServiceName}.search.windows.net' - authType: 'AAD' + authType: 'ApiKey' + credentials: { + key: searchApiKey + } isSharedToAll: true metadata: { ApiType: 'Azure' diff --git a/infra/modules/web-sites.bicep b/infra/modules/web-sites.bicep new file mode 100644 index 000000000..520f33669 --- /dev/null +++ b/infra/modules/web-sites.bicep @@ -0,0 +1,368 @@ +@description('Required. Name of the site.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Required. Type of site to deploy.') +@allowed([ + 'functionapp' // function app windows os + 'functionapp,linux' // function app linux os + 'functionapp,workflowapp' // logic app workflow + 'functionapp,workflowapp,linux' // logic app docker container + 'functionapp,linux,container' // function app linux container + 'functionapp,linux,container,azurecontainerapps' // function app linux container azure container apps + 'app,linux' // linux web app + 'app' // windows web app + 'linux,api' // linux api app + 'api' // windows api app + 'app,linux,container' // linux container app + 'app,container,windows' // windows container app +]) +param kind string + +@description('Required. The resource ID of the app service plan to use for the site.') +param serverFarmResourceId string + +@description('Optional. Azure Resource Manager ID of the customers selected Managed Environment on which to host this app.') +param managedEnvironmentId string? + +@description('Optional. Configures a site to accept only HTTPS requests. Issues redirect for HTTP requests.') +param httpsOnly bool = true + +@description('Optional. If client affinity is enabled.') +param clientAffinityEnabled bool = true + +@description('Optional. The resource ID of the app service environment to use for this resource.') +param appServiceEnvironmentResourceId string? + +import { managedIdentityAllType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The managed identity definition for this resource.') +param managedIdentities managedIdentityAllType? + +@description('Optional. The resource ID of the assigned identity to be used to access a key vault with.') +param keyVaultAccessIdentityResourceId string? + +@description('Optional. Checks if Customer provided storage account is required.') +param storageAccountRequired bool = false + +@description('Optional. Azure Resource Manager ID of the Virtual network and subnet to be joined by Regional VNET Integration. This must be of the form /subscriptions/{subscriptionName}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{vnetName}/subnets/{subnetName}.') +param virtualNetworkSubnetId string? + +@description('Optional. To enable accessing content over virtual network.') +param vnetContentShareEnabled bool = false + +@description('Optional. To enable pulling image over Virtual Network.') +param vnetImagePullEnabled bool = false + +@description('Optional. Virtual Network Route All enabled. This causes all outbound traffic to have Virtual Network Security Groups and User Defined Routes applied.') +param vnetRouteAllEnabled bool = false + +@description('Optional. Stop SCM (KUDU) site when the app is stopped.') +param scmSiteAlsoStopped bool = false + +@description('Optional. The site config object. The defaults are set to the following values: alwaysOn: true, minTlsVersion: \'1.2\', ftpsState: \'FtpsOnly\'.') +param siteConfig resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.siteConfig = { + alwaysOn: true + minTlsVersion: '1.2' + ftpsState: 'FtpsOnly' +} + +@description('Optional. The web site config.') +param configs appSettingsConfigType[]? + +@description('Optional. The Function App configuration object.') +param functionAppConfig resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.functionAppConfig? + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingFullType[]? + +@description('Optional. To enable client certificate authentication (TLS mutual authentication).') +param clientCertEnabled bool = false + +@description('Optional. Client certificate authentication comma-separated exclusion paths.') +param clientCertExclusionPaths string? + +@description(''' +Optional. This composes with ClientCertEnabled setting. +- ClientCertEnabled=false means ClientCert is ignored. +- ClientCertEnabled=true and ClientCertMode=Required means ClientCert is required. +- ClientCertEnabled=true and ClientCertMode=Optional means ClientCert is optional or accepted. +''') +@allowed([ + 'Optional' + 'OptionalInteractiveUser' + 'Required' +]) +param clientCertMode string = 'Optional' + +@description('Optional. If specified during app creation, the app is cloned from a source app.') +param cloningInfo resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.cloningInfo? + +@description('Optional. Size of the function container.') +param containerSize int? + +@description('Optional. Maximum allowed daily memory-time quota (applicable on dynamic apps only).') +param dailyMemoryTimeQuota int? + +@description('Optional. Setting this value to false disables the app (takes the app offline).') +param enabled bool = true + +@description('Optional. Hostname SSL states are used to manage the SSL bindings for app\'s hostnames.') +param hostNameSslStates resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.hostNameSslStates? + +@description('Optional. Hyper-V sandbox.') +param hyperV bool = false + +@description('Optional. Site redundancy mode.') +@allowed([ + 'ActiveActive' + 'Failover' + 'GeoRedundant' + 'Manual' + 'None' +]) +param redundancyMode string = 'None' + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string? + +@description('Optional. End to End Encryption Setting.') +param e2eEncryptionEnabled bool? + +@description('Optional. Property to configure various DNS related settings for a site.') +param dnsConfiguration resourceInput<'Microsoft.Web/sites@2024-04-01'>.properties.dnsConfiguration? + +@description('Optional. Specifies the scope of uniqueness for the default hostname during resource creation.') +@allowed([ + 'NoReuse' + 'ResourceGroupReuse' + 'SubscriptionReuse' + 'TenantReuse' +]) +param autoGeneratedDomainNameLabelScope string? + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: (managedIdentities.?systemAssigned ?? false) + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') + : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None') + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +resource app 'Microsoft.Web/sites@2024-04-01' = { + name: name + location: location + kind: kind + tags: tags + identity: identity + properties: { + managedEnvironmentId: !empty(managedEnvironmentId) ? managedEnvironmentId : null + serverFarmId: serverFarmResourceId + clientAffinityEnabled: clientAffinityEnabled + httpsOnly: httpsOnly + hostingEnvironmentProfile: !empty(appServiceEnvironmentResourceId) + ? { + id: appServiceEnvironmentResourceId + } + : null + storageAccountRequired: storageAccountRequired + keyVaultReferenceIdentity: keyVaultAccessIdentityResourceId + virtualNetworkSubnetId: virtualNetworkSubnetId + siteConfig: siteConfig + functionAppConfig: functionAppConfig + clientCertEnabled: clientCertEnabled + clientCertExclusionPaths: clientCertExclusionPaths + clientCertMode: clientCertMode + cloningInfo: cloningInfo + containerSize: containerSize + dailyMemoryTimeQuota: dailyMemoryTimeQuota + enabled: enabled + hostNameSslStates: hostNameSslStates + hyperV: hyperV + redundancyMode: redundancyMode + publicNetworkAccess: !empty(publicNetworkAccess) + ? any(publicNetworkAccess) + : (!empty(privateEndpoints) ? 'Disabled' : 'Enabled') + vnetContentShareEnabled: vnetContentShareEnabled + vnetImagePullEnabled: vnetImagePullEnabled + vnetRouteAllEnabled: vnetRouteAllEnabled + scmSiteAlsoStopped: scmSiteAlsoStopped + endToEndEncryptionEnabled: e2eEncryptionEnabled + dnsConfiguration: dnsConfiguration + autoGeneratedDomainNameLabelScope: autoGeneratedDomainNameLabelScope + } +} + +module app_config 'web-sites.config.bicep' = [ + for (config, index) in (configs ?? []): { + name: '${uniqueString(deployment().name, location)}-Site-Config-${index}' + params: { + appName: app.name + name: config.name + applicationInsightResourceId: config.?applicationInsightResourceId + storageAccountResourceId: config.?storageAccountResourceId + storageAccountUseIdentityAuthentication: config.?storageAccountUseIdentityAuthentication + properties: config.?properties + currentAppSettings: config.?retainCurrentAppSettings ?? true && config.name == 'appsettings' + ? list('${app.id}/config/appsettings', '2023-12-01').properties + : {} + } + } +] + +#disable-next-line use-recent-api-versions +resource app_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ + for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + metrics: [ + for group in (diagnosticSetting.?metricCategories ?? [{ category: 'AllMetrics' }]): { + category: group.category + enabled: group.?enabled ?? true + timeGrain: null + } + ] + logs: [ + for group in (diagnosticSetting.?logCategoriesAndGroups ?? [{ categoryGroup: 'allLogs' }]): { + categoryGroup: group.?categoryGroup + category: group.?category + enabled: group.?enabled ?? true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: app + } +] + +module app_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.11.0' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-app-PrivateEndpoint-${index}' + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites'}-${index}' + properties: { + privateLinkServiceId: app.id + groupIds: [ + privateEndpoint.?service ?? 'sites' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(app.id, '/'))}-${privateEndpoint.?service ?? 'sites'}-${index}' + properties: { + privateLinkServiceId: app.id + groupIds: [ + privateEndpoint.?service ?? 'sites' + ] + requestMessage: privateEndpoint.?manualConnectionRequestMessage ?? 'Manual approval required.' + } + } + ] + : null + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: false //As per https://azure.github.io/Azure-Verified-Modules/spec/BCPFR7/ + location: privateEndpoint.?location ?? reference( + split(privateEndpoint.subnetResourceId, '/subnets/')[0], + '2020-06-01', + 'Full' + ).location + lock: privateEndpoint.?lock ?? null + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } + } +] + +@description('The name of the site.') +output name string = app.name + +@description('The resource ID of the site.') +output resourceId string = app.id + +@description('The resource group the site was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The principal ID of the system assigned identity.') +output systemAssignedMIPrincipalId string? = app.?identity.?principalId + +@description('The location the resource was deployed into.') +output location string = app.location + +@description('Default hostname of the app.') +output defaultHostname string = app.properties.defaultHostName + +@description('Unique identifier that verifies the custom domains assigned to the app. Customer will add this ID to a txt record for verification.') +output customDomainVerificationId string = app.properties.customDomainVerificationId + +@description('The outbound IP addresses of the app.') +output outboundIpAddresses string = app.properties.outboundIpAddresses + +// ================ // +// Definitions // +// ================ // +@export() +@description('The type of an app settings configuration.') +type appSettingsConfigType = { + @description('Required. The type of config.') + name: 'appsettings' + + @description('Optional. If the provided storage account requires Identity based authentication (\'allowSharedKeyAccess\' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is \'Storage Blob Data Owner\'.') + storageAccountUseIdentityAuthentication: bool? + + @description('Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the application insight to leverage for this resource.') + applicationInsightResourceId: string? + + @description('Optional. The retain the current app settings. Defaults to true.') + retainCurrentAppSettings: bool? + + @description('Optional. The app settings key-value pairs except for AzureWebJobsStorage, AzureWebJobsDashboard, APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING.') + properties: { + @description('Required. An app settings key-value pair.') + *: string + }? +} diff --git a/infra/modules/web-sites.config.bicep b/infra/modules/web-sites.config.bicep new file mode 100644 index 000000000..130a9806b --- /dev/null +++ b/infra/modules/web-sites.config.bicep @@ -0,0 +1,91 @@ +metadata name = 'Site App Settings' +metadata description = 'This module deploys a Site App Setting.' + +@description('Conditional. The name of the parent site resource. Required if the template is used in a standalone deployment.') +param appName string + +@description('Required. The name of the config.') +@allowed([ + 'appsettings' + 'authsettings' + 'authsettingsV2' + 'azurestorageaccounts' + 'backup' + 'connectionstrings' + 'logs' + 'metadata' + 'pushsettings' + 'slotConfigNames' + 'web' +]) +param name string + +@description('Optional. The properties of the config. Note: This parameter is highly dependent on the config type, defined by its name.') +param properties object = {} + +// Parameters only relevant for the config type 'appsettings' +@description('Optional. If the provided storage account requires Identity based authentication (\'allowSharedKeyAccess\' is set to false). When set to true, the minimum role assignment required for the App Service Managed Identity to the storage account is \'Storage Blob Data Owner\'.') +param storageAccountUseIdentityAuthentication bool = false + +@description('Optional. Required if app of kind functionapp. Resource ID of the storage account to manage triggers and logging function executions.') +param storageAccountResourceId string? + +@description('Optional. Resource ID of the application insight to leverage for this resource.') +param applicationInsightResourceId string? + +@description('Optional. The current app settings.') +param currentAppSettings { + @description('Required. The key-values pairs of the current app settings.') + *: string +} = {} + +var azureWebJobsValues = !empty(storageAccountResourceId) && !storageAccountUseIdentityAuthentication + ? { + AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount!.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' + } + : !empty(storageAccountResourceId) && storageAccountUseIdentityAuthentication + ? { + AzureWebJobsStorage__accountName: storageAccount.name + AzureWebJobsStorage__blobServiceUri: storageAccount!.properties.primaryEndpoints.blob + AzureWebJobsStorage__queueServiceUri: storageAccount!.properties.primaryEndpoints.queue + AzureWebJobsStorage__tableServiceUri: storageAccount!.properties.primaryEndpoints.table + } + : {} + +var appInsightsValues = !empty(applicationInsightResourceId) + ? { + APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights!.properties.ConnectionString + } + : {} + +var expandedProperties = union(currentAppSettings, properties, azureWebJobsValues, appInsightsValues) + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightResourceId)) { + name: last(split(applicationInsightResourceId!, '/')) + scope: resourceGroup(split(applicationInsightResourceId!, '/')[2], split(applicationInsightResourceId!, '/')[4]) +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2024-01-01' existing = if (!empty(storageAccountResourceId)) { + name: last(split(storageAccountResourceId!, '/')) + scope: resourceGroup(split(storageAccountResourceId!, '/')[2], split(storageAccountResourceId!, '/')[4]) +} + +resource app 'Microsoft.Web/sites@2023-12-01' existing = { + name: appName +} + +resource config 'Microsoft.Web/sites/config@2024-04-01' = { + parent: app + #disable-next-line BCP225 + name: name + properties: expandedProperties +} + +@description('The name of the site config.') +output name string = config.name + +@description('The resource ID of the site config.') +output resourceId string = config.id + +@description('The resource group the site config was deployed into.') +output resourceGroupName string = resourceGroup().name diff --git a/infra/old/deploy_ai_foundry.bicep b/infra/old/00-older/deploy_ai_foundry.bicep similarity index 100% rename from infra/old/deploy_ai_foundry.bicep rename to infra/old/00-older/deploy_ai_foundry.bicep diff --git a/infra/old/deploy_keyvault.bicep b/infra/old/00-older/deploy_keyvault.bicep similarity index 100% rename from infra/old/deploy_keyvault.bicep rename to infra/old/00-older/deploy_keyvault.bicep diff --git a/infra/old/deploy_managed_identity.bicep b/infra/old/00-older/deploy_managed_identity.bicep similarity index 100% rename from infra/old/deploy_managed_identity.bicep rename to infra/old/00-older/deploy_managed_identity.bicep diff --git a/infra/old/macae-continer-oc.json b/infra/old/00-older/macae-continer-oc.json similarity index 100% rename from infra/old/macae-continer-oc.json rename to infra/old/00-older/macae-continer-oc.json diff --git a/infra/old/macae-continer.json b/infra/old/00-older/macae-continer.json similarity index 100% rename from infra/old/macae-continer.json rename to infra/old/00-older/macae-continer.json diff --git a/infra/old/macae-dev.bicep b/infra/old/00-older/macae-dev.bicep similarity index 100% rename from infra/old/macae-dev.bicep rename to infra/old/00-older/macae-dev.bicep diff --git a/infra/old/macae-large.bicepparam b/infra/old/00-older/macae-large.bicepparam similarity index 100% rename from infra/old/macae-large.bicepparam rename to infra/old/00-older/macae-large.bicepparam diff --git a/infra/old/macae-mini.bicepparam b/infra/old/00-older/macae-mini.bicepparam similarity index 100% rename from infra/old/macae-mini.bicepparam rename to infra/old/00-older/macae-mini.bicepparam diff --git a/infra/old/macae.bicep b/infra/old/00-older/macae.bicep similarity index 100% rename from infra/old/macae.bicep rename to infra/old/00-older/macae.bicep diff --git a/infra/old/main.bicep b/infra/old/00-older/main.bicep similarity index 100% rename from infra/old/main.bicep rename to infra/old/00-older/main.bicep diff --git a/infra/old/main2.bicep b/infra/old/00-older/main2.bicep similarity index 100% rename from infra/old/main2.bicep rename to infra/old/00-older/main2.bicep diff --git a/infra/old/resources.bicep b/infra/old/00-older/resources.bicep similarity index 100% rename from infra/old/resources.bicep rename to infra/old/00-older/resources.bicep diff --git a/infra/abbreviations.json b/infra/old/08-2025/abbreviations.json similarity index 100% rename from infra/abbreviations.json rename to infra/old/08-2025/abbreviations.json diff --git a/infra/bicepconfig.json b/infra/old/08-2025/bicepconfig.json similarity index 100% rename from infra/bicepconfig.json rename to infra/old/08-2025/bicepconfig.json diff --git a/infra/old/08-2025/main.bicep b/infra/old/08-2025/main.bicep new file mode 100644 index 000000000..8ee54772d --- /dev/null +++ b/infra/old/08-2025/main.bicep @@ -0,0 +1,1720 @@ +metadata name = 'Multi-Agent Custom Automation Engine' +metadata description = 'This module contains the resources required to deploy the Multi-Agent Custom Automation Engine solution accelerator for both Sandbox environments and WAF aligned environments.' + +@description('Set to true if you want to deploy WAF-aligned infrastructure.') +param useWafAlignedArchitecture bool + +@description('Use this parameter to use an existing AI project resource ID') +param existingFoundryProjectResourceId string = '' + +@description('Required. Name of the environment to deploy the solution into.') +param environmentName string + +@description('Required. Location for all Resources except AI Foundry.') +param solutionLocation string = resourceGroup().location + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +param existingLogAnalyticsWorkspaceId string = '' + +// Restricting deployment to only supported Azure OpenAI regions validated with GPT-4o model +@metadata({ + azd : { + type: 'location' + usageName : [ + 'OpenAI.GlobalStandard.gpt-4o, 150' + ] + } +}) +@allowed(['australiaeast', 'eastus2', 'francecentral', 'japaneast', 'norwayeast', 'swedencentral', 'uksouth', 'westus']) +@description('Azure OpenAI Location') +param aiDeploymentsLocation string + +@minLength(1) +@description('Name of the GPT model to deploy:') +param gptModelName string = 'gpt-4o' + +param gptModelVersion string = '2024-08-06' + +@minLength(1) +@description('GPT model deployment type:') +param modelDeploymentType string = 'GlobalStandard' + +@description('Optional. AI model deployment token capacity.') +param gptModelCapacity int = 150 + +@description('Set the image tag for the container images used in the solution. Default is "latest".') +param imageTag string = 'latest' + +param solutionPrefix string = 'macae-${padLeft(take(toLower(uniqueString(subscription().id, environmentName, resourceGroup().location, resourceGroup().name)), 12), 12, '0')}' + +@description('Optional. The tags to apply to all deployed Azure resources.') +param tags object = { + app: solutionPrefix + location: solutionLocation +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource.') +param logAnalyticsWorkspaceConfiguration logAnalyticsWorkspaceConfigurationType = { + enabled: true + name: 'log-${solutionPrefix}' + location: solutionLocation + sku: 'PerGB2018' + tags: tags + dataRetentionInDays: useWafAlignedArchitecture ? 365 : 30 + existingWorkspaceResourceId: existingLogAnalyticsWorkspaceId +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Application Insights resource.') +param applicationInsightsConfiguration applicationInsightsConfigurationType = { + enabled: true + name: 'appi-${solutionPrefix}' + location: solutionLocation + tags: tags + retentionInDays: useWafAlignedArchitecture ? 365 : 30 +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Managed Identity resource.') +param userAssignedManagedIdentityConfiguration userAssignedManagedIdentityType = { + enabled: true + name: 'id-${solutionPrefix}' + location: solutionLocation + tags: tags +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the backend subnet.') +param networkSecurityGroupBackendConfiguration networkSecurityGroupConfigurationType = { + enabled: true + name: 'nsg-backend-${solutionPrefix}' + location: solutionLocation + tags: tags + securityRules: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the containers subnet.') +param networkSecurityGroupContainersConfiguration networkSecurityGroupConfigurationType = { + enabled: true + name: 'nsg-containers-${solutionPrefix}' + location: solutionLocation + tags: tags + securityRules: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the Bastion subnet.') +param networkSecurityGroupBastionConfiguration networkSecurityGroupConfigurationType = { + enabled: true + name: 'nsg-bastion-${solutionPrefix}' + location: solutionLocation + tags: tags + securityRules: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine Network Security Group resource for the administration subnet.') +param networkSecurityGroupAdministrationConfiguration networkSecurityGroupConfigurationType = { + enabled: true + name: 'nsg-administration-${solutionPrefix}' + location: solutionLocation + tags: tags + securityRules: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine virtual network resource.') +param virtualNetworkConfiguration virtualNetworkConfigurationType = { + enabled: useWafAlignedArchitecture ? true : false + name: 'vnet-${solutionPrefix}' + location: solutionLocation + tags: tags + addressPrefixes: null //Default value set on module configuration + subnets: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the Multi-Agent Custom Automation Engine bastion resource.') +param bastionConfiguration bastionConfigurationType = { + enabled: true + name: 'bas-${solutionPrefix}' + location: solutionLocation + tags: tags + sku: 'Standard' + virtualNetworkResourceId: null //Default value set on module configuration + publicIpResourceName: 'pip-bas${solutionPrefix}' +} + +@description('Optional. Configuration for the Windows virtual machine.') +param virtualMachineConfiguration virtualMachineConfigurationType = { + enabled: true + name: 'vm${solutionPrefix}' + location: solutionLocation + tags: tags + adminUsername: 'adminuser' + adminPassword: useWafAlignedArchitecture? 'P@ssw0rd1234' : guid(solutionPrefix, subscription().subscriptionId) + vmSize: 'Standard_D2s_v3' + subnetResourceId: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the AI Foundry AI Services resource.') +param aiFoundryAiServicesConfiguration aiServicesConfigurationType = { + enabled: true + name: 'aisa-${solutionPrefix}' + location: aiDeploymentsLocation + sku: 'S0' + deployments: null //Default value set on module configuration + subnetResourceId: null //Default value set on module configuration + modelCapacity: gptModelCapacity +} + +@description('Optional. The configuration to apply for the AI Foundry AI Project resource.') +param aiFoundryAiProjectConfiguration aiProjectConfigurationType = { + enabled: true + name: 'aifp-${solutionPrefix}' + location: aiDeploymentsLocation + sku: 'Basic' + tags: tags +} + +@description('Optional. The configuration to apply for the Cosmos DB Account resource.') +param cosmosDbAccountConfiguration cosmosDbAccountConfigurationType = { + enabled: true + name: 'cosmos-${solutionPrefix}' + location: solutionLocation + tags: tags + subnetResourceId: null //Default value set on module configuration + sqlDatabases: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the Container App Environment resource.') +param containerAppEnvironmentConfiguration containerAppEnvironmentConfigurationType = { + enabled: true + name: 'cae-${solutionPrefix}' + location: solutionLocation + tags: tags + subnetResourceId: null //Default value set on module configuration +} + +@description('Optional. The configuration to apply for the Container App resource.') +param containerAppConfiguration containerAppConfigurationType = { + enabled: true + name: 'ca-${solutionPrefix}' + location: solutionLocation + tags: tags + environmentResourceId: null //Default value set on module configuration + concurrentRequests: '100' + containerCpu: '2.0' + containerMemory: '4.0Gi' + containerImageRegistryDomain: 'biabcontainerreg.azurecr.io' + containerImageName: 'macaebackend' + containerImageTag: imageTag + containerName: 'backend' + ingressTargetPort: 8000 + maxReplicas: 1 + minReplicas: 1 +} + +@description('Optional. The configuration to apply for the Web Server Farm resource.') +param webServerFarmConfiguration webServerFarmConfigurationType = { + enabled: true + name: 'asp-${solutionPrefix}' + location: solutionLocation + skuName: useWafAlignedArchitecture? 'P1v3' : 'B2' + skuCapacity: useWafAlignedArchitecture ? 3 : 1 + tags: tags +} + +@description('Optional. The configuration to apply for the Web Server Farm resource.') +param webSiteConfiguration webSiteConfigurationType = { + enabled: true + name: 'app-${solutionPrefix}' + location: solutionLocation + containerImageRegistryDomain: 'biabcontainerreg.azurecr.io' + containerImageName: 'macaefrontend' + containerImageTag: imageTag + containerName: 'backend' + tags: tags + environmentResourceId: null //Default value set on module configuration +} + +// ========== Resource Group Tag ========== // +resource resourceGroupTags 'Microsoft.Resources/tags@2021-04-01' = { + name: 'default' + properties: { + tags: { + ...tags + TemplateName: 'Macae' + } + } +} + +// ========== Log Analytics Workspace ========== // +// WAF best practices for Log Analytics: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-log-analytics +// Log Analytics configuration defaults +var logAnalyticsWorkspaceEnabled = logAnalyticsWorkspaceConfiguration.?enabled ?? true +var logAnalyticsWorkspaceResourceName = logAnalyticsWorkspaceConfiguration.?name ?? 'log-${solutionPrefix}' +var existingWorkspaceResourceId = logAnalyticsWorkspaceConfiguration.?existingWorkspaceResourceId ?? '' +var useExistingWorkspace = existingWorkspaceResourceId != '' + +module logAnalyticsWorkspace 'br/public:avm/res/operational-insights/workspace:0.11.2' = if (logAnalyticsWorkspaceEnabled && !useExistingWorkspace) { + name: take('avm.res.operational-insights.workspace.${logAnalyticsWorkspaceResourceName}', 64) + params: { + name: logAnalyticsWorkspaceResourceName + tags: logAnalyticsWorkspaceConfiguration.?tags ?? tags + location: logAnalyticsWorkspaceConfiguration.?location ?? solutionLocation + enableTelemetry: enableTelemetry + skuName: logAnalyticsWorkspaceConfiguration.?sku ?? 'PerGB2018' + dataRetention: logAnalyticsWorkspaceConfiguration.?dataRetentionInDays ?? 365 + diagnosticSettings: [{ useThisWorkspace: true }] + } +} + +var logAnalyticsWorkspaceId = useExistingWorkspace ? existingWorkspaceResourceId : logAnalyticsWorkspace.outputs.resourceId + +// ========== Application Insights ========== // +// WAF best practices for Application Insights: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/application-insights +// Application Insights configuration defaults +var applicationInsightsEnabled = applicationInsightsConfiguration.?enabled ?? true +var applicationInsightsResourceName = applicationInsightsConfiguration.?name ?? 'appi-${solutionPrefix}' +module applicationInsights 'br/public:avm/res/insights/component:0.6.0' = if (applicationInsightsEnabled) { + name: take('avm.res.insights.component.${applicationInsightsResourceName}', 64) + params: { + name: applicationInsightsResourceName + workspaceResourceId: logAnalyticsWorkspaceId + location: applicationInsightsConfiguration.?location ?? solutionLocation + enableTelemetry: enableTelemetry + tags: applicationInsightsConfiguration.?tags ?? tags + retentionInDays: applicationInsightsConfiguration.?retentionInDays ?? 365 + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + kind: 'web' + disableIpMasking: false + flowType: 'Bluefield' + } +} + +// ========== User assigned identity Web Site ========== // +// WAF best practices for identity and access management: https://learn.microsoft.com/en-us/azure/well-architected/security/identity-access +var userAssignedManagedIdentityEnabled = userAssignedManagedIdentityConfiguration.?enabled ?? true +var userAssignedManagedIdentityResourceName = userAssignedManagedIdentityConfiguration.?name ?? 'id-${solutionPrefix}' +module userAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.1' = if (userAssignedManagedIdentityEnabled) { + name: take('avm.res.managed-identity.user-assigned-identity.${userAssignedManagedIdentityResourceName}', 64) + params: { + name: userAssignedManagedIdentityResourceName + tags: userAssignedManagedIdentityConfiguration.?tags ?? tags + location: userAssignedManagedIdentityConfiguration.?location ?? solutionLocation + enableTelemetry: enableTelemetry + } +} + +// ========== Network Security Groups ========== // +// WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network +// WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking +var networkSecurityGroupBackendEnabled = networkSecurityGroupBackendConfiguration.?enabled ?? true +var networkSecurityGroupBackendResourceName = networkSecurityGroupBackendConfiguration.?name ?? 'nsg-backend-${solutionPrefix}' +module networkSecurityGroupBackend 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupBackendEnabled) { + name: take('avm.res.network.network-security-group.${networkSecurityGroupBackendResourceName}', 64) + params: { + name: networkSecurityGroupBackendResourceName + location: networkSecurityGroupBackendConfiguration.?location ?? solutionLocation + tags: networkSecurityGroupBackendConfiguration.?tags ?? tags + enableTelemetry: enableTelemetry + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + securityRules: networkSecurityGroupBackendConfiguration.?securityRules ?? [ + // { + // name: 'DenySshRdpOutbound' //Azure Bastion + // properties: { + // priority: 200 + // access: 'Deny' + // protocol: '*' + // direction: 'Outbound' + // sourceAddressPrefix: 'VirtualNetwork' + // sourcePortRange: '*' + // destinationAddressPrefix: '*' + // destinationPortRanges: [ + // '3389' + // '22' + // ] + // } + // } + ] + } +} + +var networkSecurityGroupContainersEnabled = networkSecurityGroupContainersConfiguration.?enabled ?? true +var networkSecurityGroupContainersResourceName = networkSecurityGroupContainersConfiguration.?name ?? 'nsg-containers-${solutionPrefix}' +module networkSecurityGroupContainers 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupContainersEnabled) { + name: take('avm.res.network.network-security-group.${networkSecurityGroupContainersResourceName}', 64) + params: { + name: networkSecurityGroupContainersResourceName + location: networkSecurityGroupContainersConfiguration.?location ?? solutionLocation + tags: networkSecurityGroupContainersConfiguration.?tags ?? tags + enableTelemetry: enableTelemetry + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + securityRules: networkSecurityGroupContainersConfiguration.?securityRules ?? [ + // { + // name: 'DenySshRdpOutbound' //Azure Bastion + // properties: { + // priority: 200 + // access: 'Deny' + // protocol: '*' + // direction: 'Outbound' + // sourceAddressPrefix: 'VirtualNetwork' + // sourcePortRange: '*' + // destinationAddressPrefix: '*' + // destinationPortRanges: [ + // '3389' + // '22' + // ] + // } + // } + ] + } +} + +var networkSecurityGroupBastionEnabled = networkSecurityGroupBastionConfiguration.?enabled ?? true +var networkSecurityGroupBastionResourceName = networkSecurityGroupBastionConfiguration.?name ?? 'nsg-bastion-${solutionPrefix}' +module networkSecurityGroupBastion 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupBastionEnabled) { + name: take('avm.res.network.network-security-group.${networkSecurityGroupBastionResourceName}', 64) + params: { + name: networkSecurityGroupBastionResourceName + location: networkSecurityGroupBastionConfiguration.?location ?? solutionLocation + tags: networkSecurityGroupBastionConfiguration.?tags ?? tags + enableTelemetry: enableTelemetry + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + securityRules: networkSecurityGroupBastionConfiguration.?securityRules ?? [ + { + name: 'AllowHttpsInBound' + properties: { + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'Internet' + destinationPortRange: '443' + destinationAddressPrefix: '*' + access: 'Allow' + priority: 100 + direction: 'Inbound' + } + } + { + name: 'AllowGatewayManagerInBound' + properties: { + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'GatewayManager' + destinationPortRange: '443' + destinationAddressPrefix: '*' + access: 'Allow' + priority: 110 + direction: 'Inbound' + } + } + { + name: 'AllowLoadBalancerInBound' + properties: { + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: 'AzureLoadBalancer' + destinationPortRange: '443' + destinationAddressPrefix: '*' + access: 'Allow' + priority: 120 + direction: 'Inbound' + } + } + { + name: 'AllowBastionHostCommunicationInBound' + properties: { + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + destinationAddressPrefix: 'VirtualNetwork' + access: 'Allow' + priority: 130 + direction: 'Inbound' + } + } + { + name: 'DenyAllInBound' + properties: { + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationPortRange: '*' + destinationAddressPrefix: '*' + access: 'Deny' + priority: 1000 + direction: 'Inbound' + } + } + { + name: 'AllowSshRdpOutBound' + properties: { + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationPortRanges: [ + '22' + '3389' + ] + destinationAddressPrefix: 'VirtualNetwork' + access: 'Allow' + priority: 100 + direction: 'Outbound' + } + } + { + name: 'AllowAzureCloudCommunicationOutBound' + properties: { + protocol: 'Tcp' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationPortRange: '443' + destinationAddressPrefix: 'AzureCloud' + access: 'Allow' + priority: 110 + direction: 'Outbound' + } + } + { + name: 'AllowBastionHostCommunicationOutBound' + properties: { + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationPortRanges: [ + '8080' + '5701' + ] + destinationAddressPrefix: 'VirtualNetwork' + access: 'Allow' + priority: 120 + direction: 'Outbound' + } + } + { + name: 'AllowGetSessionInformationOutBound' + properties: { + protocol: '*' + sourcePortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: 'Internet' + destinationPortRanges: [ + '80' + '443' + ] + access: 'Allow' + priority: 130 + direction: 'Outbound' + } + } + { + name: 'DenyAllOutBound' + properties: { + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: '*' + access: 'Deny' + priority: 1000 + direction: 'Outbound' + } + } + ] + } +} + +var networkSecurityGroupAdministrationEnabled = networkSecurityGroupAdministrationConfiguration.?enabled ?? true +var networkSecurityGroupAdministrationResourceName = networkSecurityGroupAdministrationConfiguration.?name ?? 'nsg-administration-${solutionPrefix}' +module networkSecurityGroupAdministration 'br/public:avm/res/network/network-security-group:0.5.1' = if (virtualNetworkEnabled && networkSecurityGroupAdministrationEnabled) { + name: take('avm.res.network.network-security-group.${networkSecurityGroupAdministrationResourceName}', 64) + params: { + name: networkSecurityGroupAdministrationResourceName + location: networkSecurityGroupAdministrationConfiguration.?location ?? solutionLocation + tags: networkSecurityGroupAdministrationConfiguration.?tags ?? tags + enableTelemetry: enableTelemetry + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + securityRules: networkSecurityGroupAdministrationConfiguration.?securityRules ?? [ + // { + // name: 'DenySshRdpOutbound' //Azure Bastion + // properties: { + // priority: 200 + // access: 'Deny' + // protocol: '*' + // direction: 'Outbound' + // sourceAddressPrefix: 'VirtualNetwork' + // sourcePortRange: '*' + // destinationAddressPrefix: '*' + // destinationPortRanges: [ + // '3389' + // '22' + // ] + // } + // } + ] + } +} + +// ========== Virtual Network ========== // +// WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network +// WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking +var virtualNetworkEnabled = virtualNetworkConfiguration.?enabled ?? true +var virtualNetworkResourceName = virtualNetworkConfiguration.?name ?? 'vnet-${solutionPrefix}' +module virtualNetwork 'br/public:avm/res/network/virtual-network:0.6.1' = if (virtualNetworkEnabled) { + name: take('avm.res.network.virtual-network.${virtualNetworkResourceName}', 64) + params: { + name: virtualNetworkResourceName + location: virtualNetworkConfiguration.?location ?? solutionLocation + tags: virtualNetworkConfiguration.?tags ?? tags + enableTelemetry: enableTelemetry + addressPrefixes: virtualNetworkConfiguration.?addressPrefixes ?? ['10.0.0.0/8'] + subnets: virtualNetworkConfiguration.?subnets ?? [ + { + name: 'backend' + addressPrefix: '10.0.0.0/27' + //defaultOutboundAccess: false TODO: check this configuration for a more restricted outbound access + networkSecurityGroupResourceId: networkSecurityGroupBackend.outputs.resourceId + } + { + name: 'administration' + addressPrefix: '10.0.0.32/27' + networkSecurityGroupResourceId: networkSecurityGroupAdministration.outputs.resourceId + } + { + // For Azure Bastion resources deployed on or after November 2, 2021, the minimum AzureBastionSubnet size is /26 or larger (/25, /24, etc.). + // https://learn.microsoft.com/en-us/azure/bastion/configuration-settings#subnet + name: 'AzureBastionSubnet' //This exact name is required for Azure Bastion + addressPrefix: '10.0.0.64/26' + networkSecurityGroupResourceId: networkSecurityGroupBastion.outputs.resourceId + } + { + // If you use your own vnw, you need to provide a subnet that is dedicated exclusively to the Container App environment you deploy. This subnet isn't available to other services + // https://learn.microsoft.com/en-us/azure/container-apps/networking?tabs=workload-profiles-env%2Cazure-cli#custom-vnw-configuration + name: 'containers' + addressPrefix: '10.0.2.0/23' //subnet of size /23 is required for container app + delegation: 'Microsoft.App/environments' + networkSecurityGroupResourceId: networkSecurityGroupContainers.outputs.resourceId + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Enabled' + } + ] + } +} +var bastionEnabled = bastionConfiguration.?enabled ?? true +var bastionResourceName = bastionConfiguration.?name ?? 'bas-${solutionPrefix}' + +// ========== Bastion host ========== // +// WAF best practices for virtual networks: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-network +// WAF recommendations for networking and connectivity: https://learn.microsoft.com/en-us/azure/well-architected/security/networking +module bastionHost 'br/public:avm/res/network/bastion-host:0.6.1' = if (virtualNetworkEnabled && bastionEnabled) { + name: take('avm.res.network.bastion-host.${bastionResourceName}', 64) + params: { + name: bastionResourceName + location: bastionConfiguration.?location ?? solutionLocation + skuName: bastionConfiguration.?sku ?? 'Standard' + enableTelemetry: enableTelemetry + tags: bastionConfiguration.?tags ?? tags + virtualNetworkResourceId: bastionConfiguration.?virtualNetworkResourceId ?? virtualNetwork.?outputs.?resourceId + publicIPAddressObject: { + name: bastionConfiguration.?publicIpResourceName ?? 'pip-bas${solutionPrefix}' + zones: [] + } + disableCopyPaste: false + enableFileCopy: false + enableIpConnect: true + enableShareableLink: true + } +} + +// ========== Virtual machine ========== // +// WAF best practices for virtual machines: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/virtual-machines +var virtualMachineEnabled = virtualMachineConfiguration.?enabled ?? true +var virtualMachineResourceName = virtualMachineConfiguration.?name ?? 'vm${solutionPrefix}' +module virtualMachine 'br/public:avm/res/compute/virtual-machine:0.13.0' = if (virtualNetworkEnabled && virtualMachineEnabled) { + name: take('avm.res.compute.virtual-machine.${virtualMachineResourceName}', 64) + params: { + name: virtualMachineResourceName + computerName: take(virtualMachineResourceName, 15) + location: virtualMachineConfiguration.?location ?? solutionLocation + tags: virtualMachineConfiguration.?tags ?? tags + enableTelemetry: enableTelemetry + vmSize: virtualMachineConfiguration.?vmSize ?? 'Standard_D2s_v3' + adminUsername: virtualMachineConfiguration.?adminUsername ?? 'adminuser' + adminPassword: virtualMachineConfiguration.?adminPassword ?? guid(solutionPrefix, subscription().subscriptionId) + nicConfigurations: [ + { + name: 'nic-${virtualMachineResourceName}' + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + ipConfigurations: [ + { + name: '${virtualMachineResourceName}-nic01-ipconfig01' + subnetResourceId: virtualMachineConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[1] + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + } + ] + } + ] + imageReference: { + publisher: 'microsoft-dsvm' + offer: 'dsvm-win-2022' + sku: 'winserver-2022' + version: 'latest' + } + osDisk: { + name: 'osdisk-${virtualMachineResourceName}' + createOption: 'FromImage' + managedDisk: { + storageAccountType: 'Standard_LRS' + } + diskSizeGB: 128 + caching: 'ReadWrite' + } + osType: 'Windows' + encryptionAtHost: false //The property 'securityProfile.encryptionAtHost' is not valid because the 'Microsoft.Compute/EncryptionAtHost' feature is not enabled for this subscription. + zone: 0 + extensionAadJoinConfig: { + enabled: true + typeHandlerVersion: '1.0' + } + } +} + +// ========== AI Foundry: AI Services ========== // +// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai +var openAiSubResource = 'account' +var openAiPrivateDnsZones = { + 'privatelink.cognitiveservices.azure.com': openAiSubResource + 'privatelink.openai.azure.com': openAiSubResource + 'privatelink.services.ai.azure.com': openAiSubResource +} + +module privateDnsZonesAiServices 'br/public:avm/res/network/private-dns-zone:0.7.1' = [ + for zone in objectKeys(openAiPrivateDnsZones): if (virtualNetworkEnabled && aiFoundryAIservicesEnabled) { + name: take( + 'avm.res.network.private-dns-zone.ai-services.${uniqueString(aiFoundryAiServicesResourceName,zone)}.${solutionPrefix}', + 64 + ) + params: { + name: zone + tags: tags + enableTelemetry: enableTelemetry + virtualNetworkLinks: [ + { + name: 'vnetlink-${split(zone, '.')[1]}' + virtualNetworkResourceId: virtualNetwork.outputs.resourceId + } + ] + } + } +] + +// NOTE: Required version 'Microsoft.CognitiveServices/accounts@2024-04-01-preview' not available in AVM +var useExistingFoundryProject = !empty(existingFoundryProjectResourceId) +var existingAiFoundryName = useExistingFoundryProject?split( existingFoundryProjectResourceId,'/')[8]:'' +var aiFoundryAiServicesResourceName = useExistingFoundryProject? existingAiFoundryName : aiFoundryAiServicesConfiguration.?name ?? 'aisa-${solutionPrefix}' +var aiFoundryAIservicesEnabled = aiFoundryAiServicesConfiguration.?enabled ?? true +var aiFoundryAiServicesModelDeployment = { + format: 'OpenAI' + name: gptModelName + version: gptModelVersion + sku: { + name: modelDeploymentType + //Curently the capacity is set to 140 for opinanal performance. + capacity: aiFoundryAiServicesConfiguration.?modelCapacity ?? gptModelCapacity + } + raiPolicyName: 'Microsoft.Default' +} + +module aiFoundryAiServices 'modules/account/main.bicep' = if (aiFoundryAIservicesEnabled) { + name: take('avm.res.cognitive-services.account.${aiFoundryAiServicesResourceName}', 64) + params: { + name: aiFoundryAiServicesResourceName + tags: aiFoundryAiServicesConfiguration.?tags ?? tags + location: aiFoundryAiServicesConfiguration.?location ?? aiDeploymentsLocation + enableTelemetry: enableTelemetry + projectName: 'aifp-${solutionPrefix}' + projectDescription: 'aifp-${solutionPrefix}' + existingFoundryProjectResourceId: existingFoundryProjectResourceId + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + sku: aiFoundryAiServicesConfiguration.?sku ?? 'S0' + kind: 'AIServices' + disableLocalAuth: true //Should be set to true for WAF aligned configuration + customSubDomainName: aiFoundryAiServicesResourceName + apiProperties: { + //staticsEnabled: false + } + allowProjectManagement: true + managedIdentities: { + systemAssigned: true + } + publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' + networkAcls: { + bypass: 'AzureServices' + defaultAction: (virtualNetworkEnabled) ? 'Deny' : 'Allow' + } + privateEndpoints: virtualNetworkEnabled && !useExistingFoundryProject + ? ([ + { + name: 'pep-${aiFoundryAiServicesResourceName}' + customNetworkInterfaceName: 'nic-${aiFoundryAiServicesResourceName}' + subnetResourceId: aiFoundryAiServicesConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: map(objectKeys(openAiPrivateDnsZones), zone => { + name: replace(zone, '.', '-') + privateDnsZoneResourceId: resourceId('Microsoft.Network/privateDnsZones', zone) + }) + } + } + ]) + : [] + deployments: aiFoundryAiServicesConfiguration.?deployments ?? [ + { + name: aiFoundryAiServicesModelDeployment.name + model: { + format: aiFoundryAiServicesModelDeployment.format + name: aiFoundryAiServicesModelDeployment.name + version: aiFoundryAiServicesModelDeployment.version + } + raiPolicyName: aiFoundryAiServicesModelDeployment.raiPolicyName + sku: { + name: aiFoundryAiServicesModelDeployment.sku.name + capacity: aiFoundryAiServicesModelDeployment.sku.capacity + } + } + ] + } +} + +// AI Foundry: AI Project +// WAF best practices for Open AI: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-openai +var existingAiFounryProjectName = useExistingFoundryProject ? last(split( existingFoundryProjectResourceId,'/')) : '' +var aiFoundryAiProjectName = useExistingFoundryProject ? existingAiFounryProjectName : aiFoundryAiProjectConfiguration.?name ?? 'aifp-${solutionPrefix}' + +var useExistingResourceId = !empty(existingFoundryProjectResourceId) + +module cogServiceRoleAssignmentsNew './modules/role.bicep' = if(!useExistingResourceId) { + params: { + name: 'new-${guid(containerApp.name, aiFoundryAiServices.outputs.resourceId)}' + principalId: containerApp.outputs.?systemAssignedMIPrincipalId! + aiServiceName: aiFoundryAiServices.outputs.name + } + scope: resourceGroup(subscription().subscriptionId, resourceGroup().name) +} + +module cogServiceRoleAssignmentsExisting './modules/role.bicep' = if(useExistingResourceId) { + params: { + name: 'reuse-${guid(containerApp.name, aiFoundryAiServices.outputs.aiProjectInfo.resourceId)}' + principalId: containerApp.outputs.?systemAssignedMIPrincipalId! + aiServiceName: aiFoundryAiServices.outputs.name + } + scope: resourceGroup( split(existingFoundryProjectResourceId, '/')[2], split(existingFoundryProjectResourceId, '/')[4]) +} + +// ========== Cosmos DB ========== // +// WAF best practices for Cosmos DB: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/cosmos-db +module privateDnsZonesCosmosDb 'br/public:avm/res/network/private-dns-zone:0.7.0' = if (virtualNetworkEnabled) { + name: take('avm.res.network.private-dns-zone.cosmos-db.${solutionPrefix}', 64) + params: { + name: 'privatelink.documents.azure.com' + enableTelemetry: enableTelemetry + virtualNetworkLinks: [ + { + name: 'vnetlink-cosmosdb' + virtualNetworkResourceId: virtualNetwork.outputs.resourceId + } + ] + tags: tags + } +} + +var cosmosDbAccountEnabled = cosmosDbAccountConfiguration.?enabled ?? true +var cosmosDbResourceName = cosmosDbAccountConfiguration.?name ?? 'cosmos-${solutionPrefix}' +var cosmosDbDatabaseName = 'macae' +var cosmosDbDatabaseMemoryContainerName = 'memory' +module cosmosDb 'br/public:avm/res/document-db/database-account:0.12.0' = if (cosmosDbAccountEnabled) { + name: take('avm.res.document-db.database-account.${cosmosDbResourceName}', 64) + params: { + // Required parameters + name: cosmosDbAccountConfiguration.?name ?? 'cosmos-${solutionPrefix}' + location: cosmosDbAccountConfiguration.?location ?? solutionLocation + tags: cosmosDbAccountConfiguration.?tags ?? tags + enableTelemetry: enableTelemetry + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + databaseAccountOfferType: 'Standard' + enableFreeTier: false + networkRestrictions: { + networkAclBypass: 'None' + publicNetworkAccess: virtualNetworkEnabled ? 'Disabled' : 'Enabled' + } + privateEndpoints: virtualNetworkEnabled + ? [ + { + name: 'pep-${cosmosDbResourceName}' + customNetworkInterfaceName: 'nic-${cosmosDbResourceName}' + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [{ privateDnsZoneResourceId: privateDnsZonesCosmosDb.outputs.resourceId }] + } + service: 'Sql' + subnetResourceId: cosmosDbAccountConfiguration.?subnetResourceId ?? virtualNetwork.outputs.subnetResourceIds[0] + } + ] + : [] + sqlDatabases: concat(cosmosDbAccountConfiguration.?sqlDatabases ?? [], [ + { + name: cosmosDbDatabaseName + containers: [ + { + name: cosmosDbDatabaseMemoryContainerName + paths: [ + '/session_id' + ] + kind: 'Hash' + version: 2 + } + ] + } + ]) + locations: [ + { + locationName: cosmosDbAccountConfiguration.?location ?? solutionLocation + failoverPriority: 0 + isZoneRedundant: false + } + ] + capabilitiesToAdd: [ + 'EnableServerless' + ] + sqlRoleAssignmentsPrincipalIds: [ + containerApp.outputs.?systemAssignedMIPrincipalId + ] + sqlRoleDefinitions: [ + { + // Replace this with built-in role definition Cosmos DB Built-in Data Contributor: https://docs.azure.cn/en-us/cosmos-db/nosql/security/reference-data-plane-roles#cosmos-db-built-in-data-contributor + roleType: 'CustomRole' + roleName: 'Cosmos DB SQL Data Contributor' + name: 'cosmos-db-sql-data-contributor' + dataAction: [ + 'Microsoft.DocumentDB/databaseAccounts/readMetadata' + 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' + 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' + ] + } + ] + } +} + +// ========== Backend Container App Environment ========== // +// WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps +var containerAppEnvironmentEnabled = containerAppEnvironmentConfiguration.?enabled ?? true +var containerAppEnvironmentResourceName = containerAppEnvironmentConfiguration.?name ?? 'cae-${solutionPrefix}' +module containerAppEnvironment 'modules/container-app-environment.bicep' = if (containerAppEnvironmentEnabled) { + name: take('module.container-app-environment.${containerAppEnvironmentResourceName}', 64) + params: { + name: containerAppEnvironmentResourceName + tags: containerAppEnvironmentConfiguration.?tags ?? tags + location: containerAppEnvironmentConfiguration.?location ?? solutionLocation + logAnalyticsResourceId: logAnalyticsWorkspaceId + publicNetworkAccess: 'Enabled' + zoneRedundant: false + applicationInsightsConnectionString: applicationInsights.outputs.connectionString + enableTelemetry: enableTelemetry + subnetResourceId: virtualNetworkEnabled + ? containerAppEnvironmentConfiguration.?subnetResourceId ?? virtualNetwork.?outputs.?subnetResourceIds[3] ?? '' + : '' + } +} + +// ========== Backend Container App Service ========== // +// WAF best practices for container apps: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-container-apps +var containerAppEnabled = containerAppConfiguration.?enabled ?? true +var containerAppResourceName = containerAppConfiguration.?name ?? 'ca-${solutionPrefix}' +module containerApp 'br/public:avm/res/app/container-app:0.14.2' = if (containerAppEnabled) { + name: take('avm.res.app.container-app.${containerAppResourceName}', 64) + params: { + name: containerAppResourceName + tags: containerAppConfiguration.?tags ?? tags + location: containerAppConfiguration.?location ?? solutionLocation + enableTelemetry: enableTelemetry + environmentResourceId: containerAppConfiguration.?environmentResourceId ?? containerAppEnvironment.outputs.resourceId + managedIdentities: { + systemAssigned: true //Replace with user assigned identity + userAssignedResourceIds: [userAssignedIdentity.outputs.resourceId] + } + ingressTargetPort: containerAppConfiguration.?ingressTargetPort ?? 8000 + ingressExternal: true + activeRevisionsMode: 'Single' + corsPolicy: { + allowedOrigins: [ + 'https://${webSiteName}.azurewebsites.net' + 'http://${webSiteName}.azurewebsites.net' + ] + } + scaleSettings: { + //TODO: Make maxReplicas and minReplicas parameterized + maxReplicas: containerAppConfiguration.?maxReplicas ?? 1 + minReplicas: containerAppConfiguration.?minReplicas ?? 1 + rules: [ + { + name: 'http-scaler' + http: { + metadata: { + concurrentRequests: containerAppConfiguration.?concurrentRequests ?? '100' + } + } + } + ] + } + containers: [ + { + name: containerAppConfiguration.?containerName ?? 'backend' + image: '${containerAppConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${containerAppConfiguration.?containerImageName ?? 'macaebackend'}:${containerAppConfiguration.?containerImageTag ?? 'latest'}' + resources: { + //TODO: Make cpu and memory parameterized + cpu: containerAppConfiguration.?containerCpu ?? '2.0' + memory: containerAppConfiguration.?containerMemory ?? '4.0Gi' + } + env: [ + { + name: 'COSMOSDB_ENDPOINT' + value: 'https://${cosmosDbResourceName}.documents.azure.com:443/' + } + { + name: 'COSMOSDB_DATABASE' + value: cosmosDbDatabaseName + } + { + name: 'COSMOSDB_CONTAINER' + value: cosmosDbDatabaseMemoryContainerName + } + { + name: 'AZURE_OPENAI_ENDPOINT' + value: 'https://${aiFoundryAiServicesResourceName}.openai.azure.com/' + } + { + name: 'AZURE_OPENAI_MODEL_NAME' + value: aiFoundryAiServicesModelDeployment.name + } + { + name: 'AZURE_OPENAI_DEPLOYMENT_NAME' + value: aiFoundryAiServicesModelDeployment.name + } + { + name: 'AZURE_OPENAI_API_VERSION' + value: '2025-01-01-preview' //TODO: set parameter/variable + } + { + name: 'APPLICATIONINSIGHTS_INSTRUMENTATION_KEY' + value: applicationInsights.outputs.instrumentationKey + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: applicationInsights.outputs.connectionString + } + { + name: 'AZURE_AI_SUBSCRIPTION_ID' + value: subscription().subscriptionId + } + { + name: 'AZURE_AI_RESOURCE_GROUP' + value: resourceGroup().name + } + { + name: 'AZURE_AI_PROJECT_NAME' + value: aiFoundryAiProjectName + } + { + name: 'FRONTEND_SITE_NAME' + value: 'https://${webSiteName}.azurewebsites.net' + } + { + name: 'AZURE_AI_AGENT_ENDPOINT' + value: aiFoundryAiServices.outputs.aiProjectInfo.apiEndpoint + } + { + name: 'AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME' + value: aiFoundryAiServicesModelDeployment.name + } + { + name: 'APP_ENV' + value: 'Prod' + } + ] + } + ] + } +} + +var webServerFarmEnabled = webServerFarmConfiguration.?enabled ?? true +var webServerFarmResourceName = webServerFarmConfiguration.?name ?? 'asp-${solutionPrefix}' + +// ========== Frontend server farm ========== // +// WAF best practices for web app service: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps +module webServerFarm 'br/public:avm/res/web/serverfarm:0.4.1' = if (webServerFarmEnabled) { + name: take('avm.res.web.serverfarm.${webServerFarmResourceName}', 64) + params: { + name: webServerFarmResourceName + tags: tags + location: webServerFarmConfiguration.?location ?? solutionLocation + skuName: webServerFarmConfiguration.?skuName ?? 'P1v3' + skuCapacity: webServerFarmConfiguration.?skuCapacity ?? 3 + reserved: true + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + kind: 'linux' + zoneRedundant: false //TODO: make it zone redundant for waf aligned + } +} + +// ========== Frontend web site ========== // +// WAF best practices for web app service: https://learn.microsoft.com/en-us/azure/well-architected/service-guides/app-service-web-apps +var webSiteEnabled = webSiteConfiguration.?enabled ?? true + +var webSiteName = 'app-${solutionPrefix}' +module webSite 'br/public:avm/res/web/site:0.15.1' = if (webSiteEnabled) { + name: take('avm.res.web.site.${webSiteName}', 64) + params: { + name: webSiteName + tags: webSiteConfiguration.?tags ?? tags + location: webSiteConfiguration.?location ?? solutionLocation + kind: 'app,linux,container' + enableTelemetry: enableTelemetry + serverFarmResourceId: webSiteConfiguration.?environmentResourceId ?? webServerFarm.?outputs.resourceId + appInsightResourceId: applicationInsights.outputs.resourceId + diagnosticSettings: [{ workspaceResourceId: logAnalyticsWorkspaceId }] + publicNetworkAccess: 'Enabled' //TODO: use Azure Front Door WAF or Application Gateway WAF instead + siteConfig: { + linuxFxVersion: 'DOCKER|${webSiteConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}/${webSiteConfiguration.?containerImageName ?? 'macaefrontend'}:${webSiteConfiguration.?containerImageTag ?? 'latest'}' + } + appSettingsKeyValuePairs: { + SCM_DO_BUILD_DURING_DEPLOYMENT: 'true' + DOCKER_REGISTRY_SERVER_URL: 'https://${webSiteConfiguration.?containerImageRegistryDomain ?? 'biabcontainerreg.azurecr.io'}' + WEBSITES_PORT: '3000' + WEBSITES_CONTAINER_START_TIME_LIMIT: '1800' // 30 minutes, adjust as needed + BACKEND_API_URL: 'https://${containerApp.outputs.fqdn}' + AUTH_ENABLED: 'false' + APP_ENV: 'Prod' + } + } +} + +// ============ // +// Outputs // +// ============ // + +// Add your outputs here + +@description('The default url of the website to connect to the Multi-Agent Custom Automation Engine solution.') +output webSiteDefaultHostname string = webSite.outputs.defaultHostname + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Log Analytics Workspace resource configuration.') +type logAnalyticsWorkspaceConfigurationType = { + @description('Optional. If the Log Analytics Workspace resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Log Analytics Workspace resource.') + @maxLength(63) + name: string? + + @description('Optional. Location for the Log Analytics Workspace resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to for the Log Analytics Workspace resource.') + tags: object? + + @description('Optional. The SKU for the Log Analytics Workspace resource.') + sku: ('CapacityReservation' | 'Free' | 'LACluster' | 'PerGB2018' | 'PerNode' | 'Premium' | 'Standalone' | 'Standard')? + + @description('Optional. The number of days to retain the data in the Log Analytics Workspace. If empty, it will be set to 365 days.') + @maxValue(730) + dataRetentionInDays: int? + + @description('Optional: Existing Log Analytics Workspace Resource ID') + existingWorkspaceResourceId: string? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Application Insights resource configuration.') +type applicationInsightsConfigurationType = { + @description('Optional. If the Application Insights resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Application Insights resource.') + @maxLength(90) + name: string? + + @description('Optional. Location for the Application Insights resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Application Insights resource.') + tags: object? + + @description('Optional. The retention of Application Insights data in days. If empty, Standard will be used.') + retentionInDays: (120 | 180 | 270 | 30 | 365 | 550 | 60 | 730 | 90)? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Application User Assigned Managed Identity resource configuration.') +type userAssignedManagedIdentityType = { + @description('Optional. If the User Assigned Managed Identity resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the User Assigned Managed Identity resource.') + @maxLength(128) + name: string? + + @description('Optional. Location for the User Assigned Managed Identity resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the User Assigned Managed Identity resource.') + tags: object? +} + +@export() +import { securityRuleType } from 'br/public:avm/res/network/network-security-group:0.5.1' +@description('The type for the Multi-Agent Custom Automation Engine Network Security Group resource configuration.') +type networkSecurityGroupConfigurationType = { + @description('Optional. If the Network Security Group resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Network Security Group resource.') + @maxLength(90) + name: string? + + @description('Optional. Location for the Network Security Group resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Network Security Group resource.') + tags: object? + + @description('Optional. The security rules to set for the Network Security Group resource.') + securityRules: securityRuleType[]? +} + +@export() +@description('The type for the Multi-Agent Custom Automation virtual network resource configuration.') +type virtualNetworkConfigurationType = { + @description('Optional. If the Virtual Network resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Virtual Network resource.') + @maxLength(90) + name: string? + + @description('Optional. Location for the Virtual Network resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Virtual Network resource.') + tags: object? + + @description('Optional. An array of 1 or more IP Addresses prefixes for the Virtual Network resource.') + addressPrefixes: string[]? + + @description('Optional. An array of 1 or more subnets for the Virtual Network resource.') + subnets: subnetType[]? +} + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +type subnetType = { + @description('Optional. The Name of the subnet resource.') + name: string + + @description('Conditional. The address prefix for the subnet. Required if `addressPrefixes` is empty.') + addressPrefix: string? + + @description('Conditional. List of address prefixes for the subnet. Required if `addressPrefix` is empty.') + addressPrefixes: string[]? + + @description('Optional. Application gateway IP configurations of virtual network resource.') + applicationGatewayIPConfigurations: object[]? + + @description('Optional. The delegation to enable on the subnet.') + delegation: string? + + @description('Optional. The resource ID of the NAT Gateway to use for the subnet.') + natGatewayResourceId: string? + + @description('Optional. The resource ID of the network security group to assign to the subnet.') + networkSecurityGroupResourceId: string? + + @description('Optional. enable or disable apply network policies on private endpoint in the subnet.') + privateEndpointNetworkPolicies: ('Disabled' | 'Enabled' | 'NetworkSecurityGroupEnabled' | 'RouteTableEnabled')? + + @description('Optional. enable or disable apply network policies on private link service in the subnet.') + privateLinkServiceNetworkPolicies: ('Disabled' | 'Enabled')? + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType[]? + + @description('Optional. The resource ID of the route table to assign to the subnet.') + routeTableResourceId: string? + + @description('Optional. An array of service endpoint policies.') + serviceEndpointPolicies: object[]? + + @description('Optional. The service endpoints to enable on the subnet.') + serviceEndpoints: string[]? + + @description('Optional. Set this property to false to disable default outbound connectivity for all VMs in the subnet. This property can only be set at the time of subnet creation and cannot be updated for an existing subnet.') + defaultOutboundAccess: bool? + + @description('Optional. Set this property to Tenant to allow sharing subnet with other subscriptions in your AAD tenant. This property can only be set if defaultOutboundAccess is set to false, both properties can only be set if subnet is empty.') + sharingScope: ('DelegatedServices' | 'Tenant')? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Bastion resource configuration.') +type bastionConfigurationType = { + @description('Optional. If the Bastion resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Bastion resource.') + @maxLength(90) + name: string? + + @description('Optional. Location for the Bastion resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Bastion resource.') + tags: object? + + @description('Optional. The SKU for the Bastion resource.') + sku: ('Basic' | 'Developer' | 'Premium' | 'Standard')? + + @description('Optional. The Virtual Network resource id where the Bastion resource should be deployed.') + virtualNetworkResourceId: string? + + @description('Optional. The name of the Public Ip resource created to connect to Bastion.') + publicIpResourceName: string? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine virtual machine resource configuration.') +type virtualMachineConfigurationType = { + @description('Optional. If the Virtual Machine resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Virtual Machine resource.') + @maxLength(90) + name: string? + + @description('Optional. Location for the Virtual Machine resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Virtual Machine resource.') + tags: object? + + @description('Optional. Specifies the size for the Virtual Machine resource.') + vmSize: ( + | 'Basic_A0' + | 'Basic_A1' + | 'Basic_A2' + | 'Basic_A3' + | 'Basic_A4' + | 'Standard_A0' + | 'Standard_A1' + | 'Standard_A2' + | 'Standard_A3' + | 'Standard_A4' + | 'Standard_A5' + | 'Standard_A6' + | 'Standard_A7' + | 'Standard_A8' + | 'Standard_A9' + | 'Standard_A10' + | 'Standard_A11' + | 'Standard_A1_v2' + | 'Standard_A2_v2' + | 'Standard_A4_v2' + | 'Standard_A8_v2' + | 'Standard_A2m_v2' + | 'Standard_A4m_v2' + | 'Standard_A8m_v2' + | 'Standard_B1s' + | 'Standard_B1ms' + | 'Standard_B2s' + | 'Standard_B2ms' + | 'Standard_B4ms' + | 'Standard_B8ms' + | 'Standard_D1' + | 'Standard_D2' + | 'Standard_D3' + | 'Standard_D4' + | 'Standard_D11' + | 'Standard_D12' + | 'Standard_D13' + | 'Standard_D14' + | 'Standard_D1_v2' + | 'Standard_D2_v2' + | 'Standard_D3_v2' + | 'Standard_D4_v2' + | 'Standard_D5_v2' + | 'Standard_D2_v3' + | 'Standard_D4_v3' + | 'Standard_D8_v3' + | 'Standard_D16_v3' + | 'Standard_D32_v3' + | 'Standard_D64_v3' + | 'Standard_D2s_v3' + | 'Standard_D4s_v3' + | 'Standard_D8s_v3' + | 'Standard_D16s_v3' + | 'Standard_D32s_v3' + | 'Standard_D64s_v3' + | 'Standard_D11_v2' + | 'Standard_D12_v2' + | 'Standard_D13_v2' + | 'Standard_D14_v2' + | 'Standard_D15_v2' + | 'Standard_DS1' + | 'Standard_DS2' + | 'Standard_DS3' + | 'Standard_DS4' + | 'Standard_DS11' + | 'Standard_DS12' + | 'Standard_DS13' + | 'Standard_DS14' + | 'Standard_DS1_v2' + | 'Standard_DS2_v2' + | 'Standard_DS3_v2' + | 'Standard_DS4_v2' + | 'Standard_DS5_v2' + | 'Standard_DS11_v2' + | 'Standard_DS12_v2' + | 'Standard_DS13_v2' + | 'Standard_DS14_v2' + | 'Standard_DS15_v2' + | 'Standard_DS13-4_v2' + | 'Standard_DS13-2_v2' + | 'Standard_DS14-8_v2' + | 'Standard_DS14-4_v2' + | 'Standard_E2_v3' + | 'Standard_E4_v3' + | 'Standard_E8_v3' + | 'Standard_E16_v3' + | 'Standard_E32_v3' + | 'Standard_E64_v3' + | 'Standard_E2s_v3' + | 'Standard_E4s_v3' + | 'Standard_E8s_v3' + | 'Standard_E16s_v3' + | 'Standard_E32s_v3' + | 'Standard_E64s_v3' + | 'Standard_E32-16_v3' + | 'Standard_E32-8s_v3' + | 'Standard_E64-32s_v3' + | 'Standard_E64-16s_v3' + | 'Standard_F1' + | 'Standard_F2' + | 'Standard_F4' + | 'Standard_F8' + | 'Standard_F16' + | 'Standard_F1s' + | 'Standard_F2s' + | 'Standard_F4s' + | 'Standard_F8s' + | 'Standard_F16s' + | 'Standard_F2s_v2' + | 'Standard_F4s_v2' + | 'Standard_F8s_v2' + | 'Standard_F16s_v2' + | 'Standard_F32s_v2' + | 'Standard_F64s_v2' + | 'Standard_F72s_v2' + | 'Standard_G1' + | 'Standard_G2' + | 'Standard_G3' + | 'Standard_G4' + | 'Standard_G5' + | 'Standard_GS1' + | 'Standard_GS2' + | 'Standard_GS3' + | 'Standard_GS4' + | 'Standard_GS5' + | 'Standard_GS4-8' + | 'Standard_GS4-4' + | 'Standard_GS5-16' + | 'Standard_GS5-8' + | 'Standard_H8' + | 'Standard_H16' + | 'Standard_H8m' + | 'Standard_H16m' + | 'Standard_H16r' + | 'Standard_H16mr' + | 'Standard_L4s' + | 'Standard_L8s' + | 'Standard_L16s' + | 'Standard_L32s' + | 'Standard_M64s' + | 'Standard_M64ms' + | 'Standard_M128s' + | 'Standard_M128ms' + | 'Standard_M64-32ms' + | 'Standard_M64-16ms' + | 'Standard_M128-64ms' + | 'Standard_M128-32ms' + | 'Standard_NC6' + | 'Standard_NC12' + | 'Standard_NC24' + | 'Standard_NC24r' + | 'Standard_NC6s_v2' + | 'Standard_NC12s_v2' + | 'Standard_NC24s_v2' + | 'Standard_NC24rs_v2' + | 'Standard_NC6s_v3' + | 'Standard_NC12s_v3' + | 'Standard_NC24s_v3' + | 'Standard_NC24rs_v3' + | 'Standard_ND6s' + | 'Standard_ND12s' + | 'Standard_ND24s' + | 'Standard_ND24rs' + | 'Standard_NV6' + | 'Standard_NV12' + | 'Standard_NV24')? + + @description('Optional. The username for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module.') + adminUsername: string? + + @description('Optional. The password for the administrator account on the virtual machine. Required if a virtual machine is created as part of the module.') + @secure() + adminPassword: string? + + @description('Optional. The resource ID of the subnet where the Virtual Machine resource should be deployed.') + subnetResourceId: string? +} + +@export() +import { deploymentType } from 'br/public:avm/res/cognitive-services/account:0.10.2' +@description('The type for the Multi-Agent Custom Automation Engine AI Services resource configuration.') +type aiServicesConfigurationType = { + @description('Optional. If the AI Services resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the AI Services resource.') + @maxLength(90) + name: string? + + @description('Optional. Location for the AI Services resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the AI Services resource.') + tags: object? + + @description('Optional. The SKU of the AI Services resource. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') + sku: ( + | 'C2' + | 'C3' + | 'C4' + | 'F0' + | 'F1' + | 'S' + | 'S0' + | 'S1' + | 'S10' + | 'S2' + | 'S3' + | 'S4' + | 'S5' + | 'S6' + | 'S7' + | 'S8' + | 'S9')? + + @description('Optional. The resource Id of the subnet where the AI Services private endpoint should be created.') + subnetResourceId: string? + + @description('Optional. The model deployments to set for the AI Services resource.') + deployments: deploymentType[]? + + @description('Optional. The capacity to set for AI Services GTP model.') + modelCapacity: int? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine AI Foundry AI Project resource configuration.') +type aiProjectConfigurationType = { + @description('Optional. If the AI Project resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the AI Project resource.') + @maxLength(90) + name: string? + + @description('Optional. Location for the AI Project resource deployment.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The SKU of the AI Project resource.') + sku: ('Basic' | 'Free' | 'Standard' | 'Premium')? + + @description('Optional. The tags to set for the AI Project resource.') + tags: object? +} + +import { sqlDatabaseType } from 'br/public:avm/res/document-db/database-account:0.13.0' +@export() +@description('The type for the Multi-Agent Custom Automation Engine Cosmos DB Account resource configuration.') +type cosmosDbAccountConfigurationType = { + @description('Optional. If the Cosmos DB Account resource should be deployed or not.') + enabled: bool? + @description('Optional. The name of the Cosmos DB Account resource.') + @maxLength(60) + name: string? + + @description('Optional. Location for the Cosmos DB Account resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Cosmos DB Account resource.') + tags: object? + + @description('Optional. The resource Id of the subnet where the Cosmos DB Account private endpoint should be created.') + subnetResourceId: string? + + @description('Optional. The SQL databases configuration for the Cosmos DB Account resource.') + sqlDatabases: sqlDatabaseType[]? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Container App Environment resource configuration.') +type containerAppEnvironmentConfigurationType = { + @description('Optional. If the Container App Environment resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Container App Environment resource.') + @maxLength(60) + name: string? + + @description('Optional. Location for the Container App Environment resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Container App Environment resource.') + tags: object? + + @description('Optional. The resource Id of the subnet where the Container App Environment private endpoint should be created.') + subnetResourceId: string? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Container App resource configuration.') +type containerAppConfigurationType = { + @description('Optional. If the Container App resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Container App resource.') + @maxLength(60) + name: string? + + @description('Optional. Location for the Container App resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Container App resource.') + tags: object? + + @description('Optional. The resource Id of the Container App Environment where the Container App should be created.') + environmentResourceId: string? + + @description('Optional. The maximum number of replicas of the Container App.') + maxReplicas: int? + + @description('Optional. The minimum number of replicas of the Container App.') + minReplicas: int? + + @description('Optional. The ingress target port of the Container App.') + ingressTargetPort: int? + + @description('Optional. The concurrent requests allowed for the Container App.') + concurrentRequests: string? + + @description('Optional. The name given to the Container App.') + containerName: string? + + @description('Optional. The container registry domain of the container image to be used by the Container App. Default to `biabcontainerreg.azurecr.io`') + containerImageRegistryDomain: string? + + @description('Optional. The name of the container image to be used by the Container App.') + containerImageName: string? + + @description('Optional. The tag of the container image to be used by the Container App.') + containerImageTag: string? + + @description('Optional. The CPU reserved for the Container App. Defaults to 2.0') + containerCpu: string? + + @description('Optional. The Memory reserved for the Container App. Defaults to 4.0Gi') + containerMemory: string? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Entra ID Application resource configuration.') +type entraIdApplicationConfigurationType = { + @description('Optional. If the Entra ID Application for website authentication should be deployed or not.') + enabled: bool? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Web Server Farm resource configuration.') +type webServerFarmConfigurationType = { + @description('Optional. If the Web Server Farm resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Web Server Farm resource.') + @maxLength(60) + name: string? + + @description('Optional. Location for the Web Server Farm resource.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Web Server Farm resource.') + tags: object? + + @description('Optional. The name of th SKU that will determine the tier, size and family for the Web Server Farm resource. This defaults to P1v3 to leverage availability zones.') + skuName: string? + + @description('Optional. Number of workers associated with the App Service Plan. This defaults to 3, to leverage availability zones.') + skuCapacity: int? +} + +@export() +@description('The type for the Multi-Agent Custom Automation Engine Web Site resource configuration.') +type webSiteConfigurationType = { + @description('Optional. If the Web Site resource should be deployed or not.') + enabled: bool? + + @description('Optional. The name of the Web Site resource.') + @maxLength(60) + name: string? + + @description('Optional. Location for the Web Site resource deployment.') + @metadata({ azd: { type: 'location' } }) + location: string? + + @description('Optional. The tags to set for the Web Site resource.') + tags: object? + + @description('Optional. The resource Id of the Web Site Environment where the Web Site should be created.') + environmentResourceId: string? + + @description('Optional. The name given to the Container App.') + containerName: string? + + @description('Optional. The container registry domain of the container image to be used by the Web Site. Default to `biabcontainerreg.azurecr.io`') + containerImageRegistryDomain: string? + + @description('Optional. The name of the container image to be used by the Web Site.') + containerImageName: string? + + @description('Optional. The tag of the container image to be used by the Web Site.') + containerImageTag: string? +} diff --git a/infra/old/08-2025/main.parameters.json b/infra/old/08-2025/main.parameters.json new file mode 100644 index 000000000..16b465617 --- /dev/null +++ b/infra/old/08-2025/main.parameters.json @@ -0,0 +1,102 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "aiModelDeployments": { + "value": [ + { + "name": "gpt", + "model": { + "name": "gpt-4o", + "version": "2024-08-06", + "format": "OpenAI" + }, + "sku": { + "name": "GlobalStandard", + "capacity": 140 + } + } + ] + }, + "environmentName": { + "value": "${AZURE_ENV_NAME}" + }, + "solutionLocation": { + "value": "${AZURE_LOCATION}" + }, + "aiDeploymentsLocation": { + "value": "${AZURE_ENV_OPENAI_LOCATION}" + }, + "modelDeploymentType": { + "value": "${AZURE_ENV_MODEL_DEPLOYMENT_TYPE}" + }, + "gptModelName": { + "value": "${AZURE_ENV_MODEL_NAME}" + }, + "gptModelVersion": { + "value": "${AZURE_ENV_MODEL_VERSION}" + }, + "gptModelCapacity": { + "value": "${AZURE_ENV_MODEL_CAPACITY}" + }, + "existingFoundryProjectResourceId": { + "value": "${AZURE_ENV_FOUNDRY_PROJECT_ID}" + }, + "imageTag": { + "value": "${AZURE_ENV_IMAGE_TAG}" + }, + "enableTelemetry": { + "value": "${AZURE_ENV_ENABLE_TELEMETRY}" + }, + "existingLogAnalyticsWorkspaceId": { + "value": "${AZURE_ENV_LOG_ANALYTICS_WORKSPACE_ID}" + }, + "backendExists": { + "value": "${SERVICE_BACKEND_RESOURCE_EXISTS=false}" + }, + "backendDefinition": { + "value": { + "settings": [ + { + "name": "", + "value": "${VAR}", + "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", + "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR} to use the value of 'VAR' from the current environment." + }, + { + "name": "", + "value": "${VAR_S}", + "secret": true, + "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", + "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR_S} to use the value of 'VAR_S' from the current environment." + } + ] + } + }, + "frontendExists": { + "value": "${SERVICE_FRONTEND_RESOURCE_EXISTS=false}" + }, + "frontendDefinition": { + "value": { + "settings": [ + { + "name": "", + "value": "${VAR}", + "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", + "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR} to use the value of 'VAR' from the current environment." + }, + { + "name": "", + "value": "${VAR_S}", + "secret": true, + "_comment_name": "The name of the environment variable when running in Azure. If empty, ignored.", + "_comment_value": "The value to provide. This can be a fixed literal, or an expression like ${VAR_S} to use the value of 'VAR_S' from the current environment." + } + ] + } + }, + "principalId": { + "value": "${AZURE_PRINCIPAL_ID}" + } + } +} \ No newline at end of file diff --git a/infra/modules/account/main.bicep b/infra/old/08-2025/modules/account/main.bicep similarity index 100% rename from infra/modules/account/main.bicep rename to infra/old/08-2025/modules/account/main.bicep diff --git a/infra/modules/account/modules/dependencies.bicep b/infra/old/08-2025/modules/account/modules/dependencies.bicep similarity index 100% rename from infra/modules/account/modules/dependencies.bicep rename to infra/old/08-2025/modules/account/modules/dependencies.bicep diff --git a/infra/modules/account/modules/keyVaultExport.bicep b/infra/old/08-2025/modules/account/modules/keyVaultExport.bicep similarity index 100% rename from infra/modules/account/modules/keyVaultExport.bicep rename to infra/old/08-2025/modules/account/modules/keyVaultExport.bicep diff --git a/infra/modules/account/modules/project.bicep b/infra/old/08-2025/modules/account/modules/project.bicep similarity index 100% rename from infra/modules/account/modules/project.bicep rename to infra/old/08-2025/modules/account/modules/project.bicep diff --git a/infra/modules/ai-hub.bicep b/infra/old/08-2025/modules/ai-hub.bicep similarity index 100% rename from infra/modules/ai-hub.bicep rename to infra/old/08-2025/modules/ai-hub.bicep diff --git a/infra/modules/container-app-environment.bicep b/infra/old/08-2025/modules/container-app-environment.bicep similarity index 100% rename from infra/modules/container-app-environment.bicep rename to infra/old/08-2025/modules/container-app-environment.bicep diff --git a/infra/modules/fetch-container-image.bicep b/infra/old/08-2025/modules/fetch-container-image.bicep similarity index 100% rename from infra/modules/fetch-container-image.bicep rename to infra/old/08-2025/modules/fetch-container-image.bicep diff --git a/infra/modules/role.bicep b/infra/old/08-2025/modules/role.bicep similarity index 100% rename from infra/modules/role.bicep rename to infra/old/08-2025/modules/role.bicep diff --git a/infra/scripts/Process-Sample-Data.ps1 b/infra/scripts/Process-Sample-Data.ps1 index aa9cbfd9c..eb03017f2 100644 --- a/infra/scripts/Process-Sample-Data.ps1 +++ b/infra/scripts/Process-Sample-Data.ps1 @@ -4,6 +4,7 @@ param( [string]$StorageAccount, [string]$BlobContainer, [string]$AiSearch, + [string]$AiSearchIndex, [string]$ResourceGroup ) @@ -17,7 +18,11 @@ if (-not $BlobContainer) { } if (-not $AiSearch) { - $AiSearch = $(azd env get-value AZURE_SEARCH_NAME) + $AiSearch = $(azd env get-value AZURE_AI_SEARCH_NAME) +} + +if (-not $AiSearchIndex) { + $AiSearchIndex = $(azd env get-value AZURE_AI_SEARCH_INDEX_NAME) } if (-not $ResourceGroup) { @@ -28,7 +33,7 @@ $AzSubscriptionId = $(azd env get-value AZURE_SUBSCRIPTION_ID) # Check if all required arguments are provided if (-not $StorageAccount -or -not $BlobContainer -or -not $AiSearch) { - Write-Host "Usage: .\infra\scripts\Process-Sample-Data.ps1 -StorageAccount -BlobContainer -AiSearch [-ResourceGroup ]" + Write-Host "Usage: .\infra\scripts\Process-Sample-Data.ps1 -StorageAccount -BlobContainer -AiSearch [-AiSearchIndex ] [-ResourceGroup ]" exit 1 } @@ -219,7 +224,7 @@ Write-Host "Requirements installed" # Run the Python script to index data Write-Host "Running the python script to index data" -$process = Start-Process -FilePath $pythonCmd -ArgumentList "infra/scripts/index_datasets.py", $StorageAccount, $BlobContainer, $AiSearch -Wait -NoNewWindow -PassThru +$process = Start-Process -FilePath $pythonCmd -ArgumentList "infra/scripts/index_datasets.py", $StorageAccount, $BlobContainer, $AiSearch, $AiSearchIndex -Wait -NoNewWindow -PassThru if ($process.ExitCode -ne 0) { Write-Host "Error: Indexing python script execution failed." diff --git a/infra/scripts/Team-Config-And-Data.ps1 b/infra/scripts/Team-Config-And-Data.ps1 new file mode 100644 index 000000000..1cd1fb796 --- /dev/null +++ b/infra/scripts/Team-Config-And-Data.ps1 @@ -0,0 +1,74 @@ +#Requires -Version 7.0 + +param( + [string]$backendUrl, + [string]$DirectoryPath, + [string]$StorageAccount, + [string]$BlobContainer, + [string]$AiSearch, + [string]$AiSearchIndex, + [string]$ResourceGroup +) + +# Get parameters from azd env, if not provided +if (-not $backendUrl) { + $backendUrl = $(azd env get-value BACKEND_URL) +} +if (-not $DirectoryPath) { + $DirectoryPath = "data/agent_teams" +} +if (-not $StorageAccount) { + $StorageAccount = $(azd env get-value AZURE_STORAGE_ACCOUNT_NAME) +} + +if (-not $BlobContainer) { + $BlobContainer = $(azd env get-value AZURE_STORAGE_CONTAINER_NAME) +} + +if (-not $AiSearch) { + $AiSearch = $(azd env get-value AZURE_AI_SEARCH_NAME) +} + +if (-not $AiSearchIndex) { + $AiSearchIndex = $(azd env get-value AZURE_AI_SEARCH_INDEX_NAME) +} + +if (-not $ResourceGroup) { + $ResourceGroup = $(azd env get-value AZURE_RESOURCE_GROUP) +} + +# Check if all required arguments are provided +if (-not $backendUrl -or -not $DirectoryPath -or -not $StorageAccount -or -not $BlobContainer -or -not $AiSearch -or -not $AiSearchIndex -or -not $ResourceGroup) { + Write-Host "Usage: .\Team-Config-And-Data.ps1 -backendUrl -DirectoryPath -StorageAccount -BlobContainer -AiSearch [-AiSearchIndex ] [-ResourceGroup ]" + exit 1 +} + +$isTeamConfigFailed = $false +$isSampleDataFailed = $false +# Upload Team Configuration +Write-Host "Uploading Team Configuration..." +try { + .\infra\scripts\Upload-Team-Config.ps1 -backendUrl $backendUrl -DirectoryPath $DirectoryPath +} catch { + Write-Host "Error: Uploading team configuration failed." + $isTeamConfigFailed = $true +} + +Write-Host "`n----------------------------------------" +Write-Host "----------------------------------------`n" + +# Process Sample Data +Write-Host "Processing Sample Data..." +try { + .\infra\scripts\Process-Sample-Data.ps1 -StorageAccount $StorageAccount -BlobContainer $BlobContainer -AiSearch $AiSearch -AiSearchIndex $AiSearchIndex -ResourceGroup $ResourceGroup +} catch { + Write-Host "Error: Processing sample data failed." + $isSampleDataFailed = $true +} + +if ($isTeamConfigFailed -or $isSampleDataFailed) { + Write-Host "`nOne or more tasks failed. Please check the error messages above." + exit 1 +} else { + Write-Host "`nBoth team configuration upload and sample data processing completed successfully." +} diff --git a/infra/scripts/Upload-Team-Config.ps1 b/infra/scripts/Upload-Team-Config.ps1 new file mode 100644 index 000000000..342524d87 --- /dev/null +++ b/infra/scripts/Upload-Team-Config.ps1 @@ -0,0 +1,154 @@ +#Requires -Version 7.0 + +param( + [string]$backendUrl, + [string]$DirectoryPath +) + +# Get parameters from azd env, if not provided +if (-not $backendUrl) { + $backendUrl = $(azd env get-value BACKEND_URL) +} +if (-not $DirectoryPath) { + $DirectoryPath = "data/agent_teams" +} + +$AzSubscriptionId = $(azd env get-value AZURE_SUBSCRIPTION_ID) + +# Check if all required arguments are provided +if (-not $backendUrl -or -not $DirectoryPath) { + Write-Host "Usage: .\infra\scripts\Upload-Team-Config.ps1 -backendUrl -DirectoryPath " + exit 1 +} + +# Authenticate with Azure +try { + $currentAzContext = az account show | ConvertFrom-Json -ErrorAction Stop + Write-Host "Already authenticated with Azure." +} catch { + Write-Host "Not authenticated with Azure. Attempting to authenticate..." + Write-Host "Authenticating with Azure CLI..." + az login + if ($LASTEXITCODE -ne 0) { + Write-Host "Authentication failed." + exit 1 + } + $currentAzContext = az account show | ConvertFrom-Json +} + +# Check if user has selected the correct subscription +$currentSubscriptionId = $currentAzContext.id +$currentSubscriptionName = $currentAzContext.name +if ($currentSubscriptionId -ne $AzSubscriptionId) { + Write-Host "Current selected subscription is $currentSubscriptionName ( $currentSubscriptionId )." + $confirmation = Read-Host "Do you want to continue with this subscription? (y/n)" + if ($confirmation.ToLower() -ne "y") { + Write-Host "Fetching available subscriptions..." + $availableSubscriptions = (az account list --query "[?state=='Enabled']" | ConvertFrom-Json -AsHashtable) + $subscriptionArray = $availableSubscriptions | ForEach-Object { + [PSCustomObject]@{ Name = $_.name; Id = $_.id } + } + do { + Write-Host "" + Write-Host "Available Subscriptions:" + Write-Host "========================" + for ($i = 0; $i -lt $subscriptionArray.Count; $i++) { + Write-Host "$($i+1). $($subscriptionArray[$i].Name) ( $($subscriptionArray[$i].Id) )" + } + Write-Host "========================" + Write-Host "" + [int]$subscriptionIndex = Read-Host "Enter the number of the subscription (1-$($subscriptionArray.Count)) to use" + if ($subscriptionIndex -ge 1 -and $subscriptionIndex -le $subscriptionArray.Count) { + $selectedSubscription = $subscriptionArray[$subscriptionIndex-1] + $selectedSubscriptionName = $selectedSubscription.Name + $selectedSubscriptionId = $selectedSubscription.Id + $result = az account set --subscription $selectedSubscriptionId + if ($LASTEXITCODE -eq 0) { + Write-Host "Switched to subscription: $selectedSubscriptionName ( $selectedSubscriptionId )" + break + } else { + Write-Host "Failed to switch to subscription: $selectedSubscriptionName ( $selectedSubscriptionId )." + } + } else { + Write-Host "Invalid selection. Please try again." + } + } while ($true) + } else { + Write-Host "Proceeding with the current subscription: $currentSubscriptionName ( $currentSubscriptionId )" + az account set --subscription $currentSubscriptionId + } +} else { + Write-Host "Proceeding with the subscription: $currentSubscriptionName ( $currentSubscriptionId )" + az account set --subscription $currentSubscriptionId +} + +$userPrincipalId = $(az ad signed-in-user show --query id -o tsv) + +# Determine the correct Python command +$pythonCmd = $null + +try { + $pythonVersion = (python --version) 2>&1 + if ($pythonVersion -match "Python \d") { + $pythonCmd = "python" + } +} +catch { + # Do nothing, try python3 next +} + +if (-not $pythonCmd) { + try { + $pythonVersion = (python3 --version) 2>&1 + if ($pythonVersion -match "Python \d") { + $pythonCmd = "python3" + } + } + catch { + Write-Host "Python is not installed on this system or it is not added in the PATH." + exit 1 + } +} + +if (-not $pythonCmd) { + Write-Host "Python is not installed on this system or it is not added in the PATH." + exit 1 +} + +# Create virtual environment +$venvPath = "infra/scripts/scriptenv" +if (Test-Path $venvPath) { + Write-Host "Virtual environment already exists. Skipping creation." +} else { + Write-Host "Creating virtual environment" + & $pythonCmd -m venv $venvPath +} + +# Activate the virtual environment +$activateScript = "" +if (Test-Path (Join-Path -Path $venvPath -ChildPath "bin/Activate.ps1")) { + $activateScript = Join-Path -Path $venvPath -ChildPath "bin/Activate.ps1" +} elseif (Test-Path (Join-Path -Path $venvPath -ChildPath "Scripts/Activate.ps1")) { + $activateScript = Join-Path -Path $venvPath -ChildPath "Scripts/Activate.ps1" +} +if ($activateScript) { + Write-Host "Activating virtual environment" + . $activateScript +} else { + Write-Host "Error activating virtual environment. Requirements may be installed globally." +} + +# Install the requirements +Write-Host "Installing requirements" +pip install --quiet -r infra/scripts/requirements.txt +Write-Host "Requirements installed" + +# Run the Python script to upload team configuration +Write-Host "Running the python script to upload team configuration" +$process = Start-Process -FilePath $pythonCmd -ArgumentList "infra/scripts/upload_team_config.py", $backendUrl, $DirectoryPath, $userPrincipalId -Wait -NoNewWindow -PassThru +if ($process.ExitCode -ne 0) { + Write-Host "Error: Team configuration upload failed." + exit 1 +} + +Write-Host "Script executed successfully. Team configuration uploaded." diff --git a/infra/scripts/index_datasets.py b/infra/scripts/index_datasets.py index 618977e96..d0acfe6a5 100644 --- a/infra/scripts/index_datasets.py +++ b/infra/scripts/index_datasets.py @@ -1,89 +1,82 @@ from azure.identity import AzureCliCredential from azure.search.documents import SearchClient from azure.search.documents.indexes import SearchIndexClient -from azure.search.documents.indexes.models import SearchIndex, SimpleField, SearchField, SearchFieldDataType -from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient -import csv +from azure.search.documents.indexes.models import SearchIndex, SimpleField, SearchableField, SearchFieldDataType +from azure.storage.blob import BlobServiceClient import sys -import io -if len(sys.argv) > 1: - storage_account_name = sys.argv[1] - blob_container_name = sys.argv[2] - ai_search_endpoint = sys.argv[3] - if not ai_search_endpoint.__contains__("search.windows.net"): - ai_search_endpoint = f"https://{ai_search_endpoint}.search.windows.net" -else: - print("Usage: python index_datasets.py ") +if len(sys.argv) < 4: + print("Usage: python index_datasets.py []") sys.exit(1) -credential = AzureCliCredential() +storage_account_name = sys.argv[1] +blob_container_name = sys.argv[2] +ai_search_endpoint = sys.argv[3] +ai_search_index_name = sys.argv[4] if len(sys.argv) > 4 else "sample-dataset-index" +if not ai_search_endpoint.__contains__("search.windows.net"): + ai_search_endpoint = f"https://{ai_search_endpoint}.search.windows.net" -blob_service_client = BlobServiceClient(account_url=f"https://{storage_account_name}.blob.core.windows.net", credential=credential) -container_client = blob_service_client.get_container_client(blob_container_name) +credential = AzureCliCredential() try: + blob_service_client = BlobServiceClient(account_url=f"https://{storage_account_name}.blob.core.windows.net", credential=credential) + container_client = blob_service_client.get_container_client(blob_container_name) print("Fetching files in container...") - blob_list = container_client.list_blobs() + blob_list = list(container_client.list_blobs()) except Exception as e: print(f"Error fetching files: {e}") sys.exit(1) success_count = 0 fail_count = 0 +data_list = [] + +try: + index_fields = [ + SimpleField(name="id", type=SearchFieldDataType.String, key=True), + SearchableField(name="content", type=SearchFieldDataType.String, searchable=True), + SearchableField(name="title", type=SearchFieldDataType.String, searchable=True, filterable=True) + ] + index = SearchIndex(name=ai_search_index_name, fields=index_fields) + + print("Creating or updating Azure Search index...") + search_index_client = SearchIndexClient(endpoint=ai_search_endpoint, credential=credential) + index_result = search_index_client.create_or_update_index(index=index) + print(f"Index '{ai_search_index_name}' created or updated successfully.") +except Exception as e: + print(f"Error creating/updating index: {e}") + sys.exit(1) -for blob in blob_list: +for idx, blob in enumerate(blob_list, start=1): if blob.name.endswith(".csv"): - index_name = blob.name.replace(".csv", "").lower() + title = blob.name.replace(".csv", "") csv_data = container_client.download_blob(blob.name).readall() - data_list = [] + try: print(f"Reading data from blob: {blob.name}...") csv_text = csv_data.decode('utf-8') - csv_reader = csv.DictReader(io.StringIO(csv_text)) - for row in csv_reader: - data_list.append(row) - print(f"Loaded {len(data_list)} records from CSV file - {blob.name}.") + data_list.append({ + "content": csv_text, + "id": str(idx), + "title": title + }) + success_count += 1 except Exception as e: print(f"Error reading CSV file - {blob.name}: {e}") fail_count += 1 continue - if not data_list: - print(f"No data found in CSV file - {blob.name}. Skipping.") - fail_count += 1 - continue - - headers = list(data_list[0].keys()) - - index_fields = [ SimpleField(name="Id", type=SearchFieldDataType.String, key=True) ] - for header in headers: - index_fields.append(SearchField(name=header, type=SearchFieldDataType.String, searchable=True)) - - index = SearchIndex(name=index_name, fields=index_fields) - - try: - print("Creating or updating Azure Search index...") - search_index_client = SearchIndexClient(endpoint=ai_search_endpoint, credential=credential) - index_result = search_index_client.create_or_update_index(index=index) - print(f"Index '{index_name}' created or updated successfully.") - except Exception as e: - print(f"Error creating/updating index: {e}") - fail_count += 1 - continue - - for idx, item in enumerate(data_list, start=1): - item["Id"] = str(idx) +if not data_list: + print(f"No data to upload to Azure Search index. Success: {success_count}, Failed: {fail_count}") + sys.exit(1) - try: - print("Uploading documents to the index...") - search_client = SearchClient(endpoint=ai_search_endpoint, index_name=index_name, credential=credential) - result = search_client.upload_documents(documents=data_list) - print(f"Uploaded {len(data_list)} documents.") - success_count += 1 - except Exception as e: - print(f"Error uploading documents: {e}") - fail_count += 1 - continue +try: + print("Uploading documents to the index...") + search_client = SearchClient(endpoint=ai_search_endpoint, index_name=ai_search_index_name, credential=credential) + result = search_client.upload_documents(documents=data_list) + print(f"Uploaded {len(data_list)} documents.") +except Exception as e: + print(f"Error uploading documents: {e}") + sys.exit(1) print(f"Processing complete. Success: {success_count}, Failed: {fail_count}") \ No newline at end of file diff --git a/infra/scripts/process_sample_data.sh b/infra/scripts/process_sample_data.sh index 787a5c7fa..a9521dc75 100644 --- a/infra/scripts/process_sample_data.sh +++ b/infra/scripts/process_sample_data.sh @@ -4,7 +4,8 @@ storageAccount="$1" blobContainer="$2" aiSearch="$3" -resourceGroup="$4" +aiSearchIndex="$4" +resourceGroup="$5" # get parameters from azd env, if not provided if [ -z "$storageAccount" ]; then @@ -16,7 +17,11 @@ if [ -z "$blobContainer" ]; then fi if [ -z "$aiSearch" ]; then - aiSearch=$(azd env get-value AZURE_SEARCH_NAME) + aiSearch=$(azd env get-value AZURE_AI_SEARCH_NAME) +fi + +if [ -z "$aiSearchIndex" ]; then + aiSearchIndex=$(azd env get-value AZURE_AI_SEARCH_INDEX_NAME) fi if [ -z "$resourceGroup" ]; then @@ -27,7 +32,7 @@ azSubscriptionId=$(azd env get-value AZURE_SUBSCRIPTION_ID) # Check if all required arguments are provided if [ -z "$storageAccount" ] || [ -z "$blobContainer" ] || [ -z "$aiSearch" ]; then - echo "Usage: $0 [ResourceGroup]" + echo "Usage: $0 [AISearchIndexName] [ResourceGroupName]" exit 1 fi @@ -127,10 +132,10 @@ fi echo "Files uploaded successfully to blob storage." # Determine the correct Python command -if command -v python3 && python3 --version &> /dev/null; then - PYTHON_CMD="python3" -elif command -v python && python --version &> /dev/null; then +if command -v python && python --version &> /dev/null; then PYTHON_CMD="python" +elif command -v python3 && python3 --version &> /dev/null; then + PYTHON_CMD="python3" else echo "Python is not installed on this system. Or it is not added in the PATH." exit 1 @@ -161,7 +166,7 @@ pip install --quiet -r infra/scripts/requirements.txt echo "Requirements installed" echo "Running the python script to index data" -python infra/scripts/index_datasets.py "$storageAccount" "$blobContainer" "$aiSearch" +$PYTHON_CMD infra/scripts/index_datasets.py "$storageAccount" "$blobContainer" "$aiSearch" "$aiSearchIndex" if [ $? -ne 0 ]; then echo "Error: Indexing python script execution failed." exit 1 diff --git a/infra/scripts/requirements.txt b/infra/scripts/requirements.txt index 11cd7cebc..67ba55e5a 100644 --- a/infra/scripts/requirements.txt +++ b/infra/scripts/requirements.txt @@ -1,3 +1,4 @@ -azure-search-documents == 11.5.3 -azure-identity == 1.24.0 -azure-storage-blob == 12.26.0 \ No newline at end of file +azure-search-documents==11.5.3 +azure-identity==1.24.0 +azure-storage-blob==12.26.0 +requests==2.32.5 \ No newline at end of file diff --git a/infra/scripts/team_config_and_data.sh b/infra/scripts/team_config_and_data.sh new file mode 100644 index 000000000..baa1a29a2 --- /dev/null +++ b/infra/scripts/team_config_and_data.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# Variables +backendUrl=$1 +directoryPath=$2 +storageAccount="$3" +blobContainer="$4" +aiSearch="$5" +aiSearchIndex="$6" +resourceGroup="$7" + +# get parameters from azd env, if not provided as arguments +if [ -z "$directoryPath" ]; then + directoryPath="data/agent_teams" +fi + +if [ -z "$backendUrl" ]; then + backendUrl=$(azd env get-value BACKEND_URL) +fi + +if [ -z "$storageAccount" ]; then + storageAccount=$(azd env get-value AZURE_STORAGE_ACCOUNT_NAME) +fi + +if [ -z "$blobContainer" ]; then + blobContainer=$(azd env get-value AZURE_STORAGE_CONTAINER_NAME) +fi + +if [ -z "$aiSearch" ]; then + aiSearch=$(azd env get-value AZURE_AI_SEARCH_NAME) +fi + +if [ -z "$aiSearchIndex" ]; then + aiSearchIndex=$(azd env get-value AZURE_AI_SEARCH_INDEX_NAME) +fi + +if [ -z "$resourceGroup" ]; then + resourceGroup=$(azd env get-value AZURE_RESOURCE_GROUP) +fi + +# Check if all required arguments are provided +if [ -z "$backendUrl" ] || [ -z "$directoryPath" ] || [ -z "$storageAccount" ] || [ -z "$blobContainer" ] || [ -z "$aiSearch" ]; then + echo "Usage: $0 [AISearchIndexName] [ResourceGroupName]" + exit 1 +fi + + +isTeamConfigFailed=false +isSampleDataFailed=false + +echo "Uploading team configuration..." +bash infra/scripts/upload_team_config.sh "$backendUrl" "$directoryPath" +if [ $? -ne 0 ]; then + echo "Error: Team configuration upload failed." + isTeamConfigFailed=true +fi + +echo "" +echo "----------------------------------------" +echo "----------------------------------------" +echo "" + +echo "Processing sample data..." +bash infra/scripts/process_sample_data.sh "$storageAccount" "$blobContainer" "$aiSearch" "$aiSearchIndex" "$resourceGroup" +if [ $? -ne 0 ]; then + echo "Error: Sample data processing failed." + isSampleDataFailed=true +fi + +if [ "$isTeamConfigFailed" = true ] || [ "$isSampleDataFailed" = true ]; then + echo "One or more processes failed." + exit 1 +fi + +echo "Both team configuration upload and sample data processing completed successfully." \ No newline at end of file diff --git a/infra/scripts/upload_team_config.py b/infra/scripts/upload_team_config.py new file mode 100644 index 000000000..7aafbac88 --- /dev/null +++ b/infra/scripts/upload_team_config.py @@ -0,0 +1,65 @@ +import sys +import os +import requests + +if len(sys.argv) < 2: + print("Usage: python upload_team_config.py []") + sys.exit(1) + +backend_url = sys.argv[1] +directory_path = sys.argv[2] +user_principal_id = sys.argv[3] if len(sys.argv) > 3 else "00000000-0000-0000-0000-000000000000" + +# Convert to absolute path if provided as relative +directory_path = os.path.abspath(directory_path) +print(f"Scanning directory: {directory_path}") + +files_to_process = [ + ("hr.json", "00000000-0000-0000-0000-000000000001"), + ("marketing.json", "00000000-0000-0000-0000-000000000002"), + ("retail.json", "00000000-0000-0000-0000-000000000003"), +] + +upload_endpoint = backend_url.rstrip('/') + '/api/v3/upload_team_config' + +# Process each JSON file in the directory +uploaded_count = 0 +for filename, team_id in files_to_process: + file_path = os.path.join(directory_path, filename) + if os.path.isfile(file_path): + print(f"Uploading file: {filename}") + try: + with open(file_path, 'rb') as file_data: + files = { + 'file': (filename, file_data, 'application/json') + } + headers = { + 'x-ms-client-principal-id': user_principal_id + } + params = { + 'team_id': team_id + } + response = requests.post( + upload_endpoint, + files=files, + headers=headers, + params=params + ) + if response.status_code == 200: + try: + resp_json = response.json() + if resp_json.get("status") == "success": + print(f"Successfully uploaded team configuration: {resp_json.get('name')} (team_id: {resp_json.get('team_id')})") + uploaded_count += 1 + else: + print(f"Upload failed for {filename}. Response: {resp_json}") + except Exception as e: + print(f"Error parsing response for {filename}: {str(e)}") + else: + print(f"Failed to upload {filename}. Status code: {response.status_code}, Response: {response.text}") + except Exception as e: + print(f"Error processing {filename}: {str(e)}") + else: + print(f"File not found: {filename}") + +print(f"Completed uploading {uploaded_count} team configurations") \ No newline at end of file diff --git a/infra/scripts/upload_team_config.sh b/infra/scripts/upload_team_config.sh new file mode 100644 index 000000000..60875f088 --- /dev/null +++ b/infra/scripts/upload_team_config.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +# Variables +backendUrl=$1 +directoryPath=$2 + +# get parameters from azd env, if not provided as arguments +if [ -z "$directoryPath" ]; then + directoryPath="data/agent_teams" +fi + +if [ -z "$backendUrl" ]; then + backendUrl=$(azd env get-value BACKEND_URL) +fi + +azSubscriptionId=$(azd env get-value AZURE_SUBSCRIPTION_ID) + +if [ -z "$backendUrl" ] || [ -z "$directoryPath" ]; then + echo "Error: Missing required arguments." + echo "Usage: $0 " + exit 1 +fi + +# Authenticate with Azure +if az account show &> /dev/null; then + echo "Already authenticated with Azure." +else + echo "Not authenticated with Azure. Attempting to authenticate..." + echo "Authenticating with Azure CLI..." + az login +fi + +#check if user has selected the correct subscription +currentSubscriptionId=$(az account show --query id -o tsv) +currentSubscriptionName=$(az account show --query name -o tsv) +if [ "$currentSubscriptionId" != "$azSubscriptionId" ]; then + echo "Current selected subscription is $currentSubscriptionName ( $currentSubscriptionId )." + read -rp "Do you want to continue with this subscription?(y/n): " confirmation + if [[ "$confirmation" != "y" && "$confirmation" != "Y" ]]; then + echo "Fetching available subscriptions..." + availableSubscriptions=$(az account list --query "[?state=='Enabled'].[name,id]" --output tsv) + while true; do + echo "" + echo "Available Subscriptions:" + echo "========================" + echo "$availableSubscriptions" | awk '{printf "%d. %s ( %s )\n", NR, $1, $2}' + echo "========================" + echo "" + read -rp "Enter the number of the subscription (1-$(echo "$availableSubscriptions" | wc -l)) to use: " subscriptionIndex + if [[ "$subscriptionIndex" =~ ^[0-9]+$ ]] && [ "$subscriptionIndex" -ge 1 ] && [ "$subscriptionIndex" -le $(echo "$availableSubscriptions" | wc -l) ]; then + selectedSubscription=$(echo "$availableSubscriptions" | sed -n "${subscriptionIndex}p") + selectedSubscriptionName=$(echo "$selectedSubscription" | cut -f1) + selectedSubscriptionId=$(echo "$selectedSubscription" | cut -f2) + + # Set the selected subscription + if az account set --subscription "$selectedSubscriptionId"; then + echo "Switched to subscription: $selectedSubscriptionName ( $selectedSubscriptionId )" + break + else + echo "Failed to switch to subscription: $selectedSubscriptionName ( $selectedSubscriptionId )." + fi + else + echo "Invalid selection. Please try again." + fi + done + else + echo "Proceeding with the current subscription: $currentSubscriptionName ( $currentSubscriptionId )" + az account set --subscription "$currentSubscriptionId" + fi +else + echo "Proceeding with the subscription: $currentSubscriptionName ( $currentSubscriptionId )" + az account set --subscription "$currentSubscriptionId" +fi + +userPrincipalId=$(az ad signed-in-user show --query id -o tsv) + +# Determine the correct Python command +if command -v python && python --version &> /dev/null; then + PYTHON_CMD="python" +elif command -v python3 && python3 --version &> /dev/null; then + PYTHON_CMD="python3" +else + echo "Python is not installed on this system. Or it is not added in the PATH." + exit 1 +fi + +# create virtual environment +if [ -d "infra/scripts/scriptenv" ]; then + echo "Virtual environment already exists. Skipping creation." +else + echo "Creating virtual environment" + $PYTHON_CMD -m venv infra/scripts/scriptenv +fi + +# Activate the virtual environment +if [ -f "infra/scripts/scriptenv/bin/activate" ]; then + echo "Activating virtual environment (Linux/macOS)" + source "infra/scripts/scriptenv/bin/activate" +elif [ -f "infra/scripts/scriptenv/Scripts/activate" ]; then + echo "Activating virtual environment (Windows)" + source "infra/scripts/scriptenv/Scripts/activate" +else + echo "Error activating virtual environment. Requirements may be installed globally." +fi + +# Install the requirements +echo "Installing requirements" +pip install --quiet -r infra/scripts/requirements.txt +echo "Requirements installed" + +echo "Running the python script to upload team configuration" +$PYTHON_CMD infra/scripts/upload_team_config.py "$backendUrl" "$directoryPath" "$userPrincipalId" +if [ $? -ne 0 ]; then + echo "Error: Team configuration upload failed." + exit 1 +fi + +echo "Script executed successfully. Team configuration uploaded." \ No newline at end of file diff --git a/src/backend/common/config/app_config.py b/src/backend/common/config/app_config.py index ba01909fa..42ca8f9ef 100644 --- a/src/backend/common/config/app_config.py +++ b/src/backend/common/config/app_config.py @@ -69,15 +69,15 @@ def __init__(self): self.AZURE_AI_PROJECT_ENDPOINT = self._get_optional("AZURE_AI_PROJECT_ENDPOINT") # Azure Search settings - self.AZURE_SEARCH_ENDPOINT = self._get_optional("AZURE_SEARCH_ENDPOINT") + self.AZURE_SEARCH_ENDPOINT = self._get_optional("AZURE_AI_SEARCH_ENDPOINT") # Optional MCP server endpoint (for local MCP server or remote) # Example: http://127.0.0.1:8000/mcp self.MCP_SERVER_ENDPOINT = self._get_optional("MCP_SERVER_ENDPOINT") self.MCP_SERVER_NAME = self._get_optional("MCP_SERVER_NAME", "MCPGreetingServer") self.MCP_SERVER_DESCRIPTION = self._get_optional("MCP_SERVER_DESCRIPTION", "MCP server with greeting and planning tools") - self.TENANT_ID = self._get_optional("TENANT_ID") - self.CLIENT_ID = self._get_optional("CLIENT_ID") + self.TENANT_ID = self._get_optional("AZURE_TENANT_ID") + self.CLIENT_ID = self._get_optional("AZURE_CLIENT_ID") self.AZURE_AI_SEARCH_CONNECTION_NAME = self._get_optional("AZURE_AI_SEARCH_CONNECTION_NAME") self.AZURE_AI_SEARCH_INDEX_NAME = self._get_optional("AZURE_AI_SEARCH_INDEX_NAME") self.AZURE_AI_SEARCH_ENDPOINT = self._get_optional("AZURE_AI_SEARCH_ENDPOINT") @@ -115,17 +115,17 @@ def get_azure_credential(self, client_id=None): ) # CodeQL [SM05139] Okay use of DefaultAzureCredential as it is only used in development else: return ManagedIdentityCredential(client_id=client_id) - + def get_azure_credentials(self): """Retrieve Azure credentials, either from environment variables or managed identity.""" if self._azure_credentials is None: - self._azure_credentials = self.get_azure_credential() + self._azure_credentials = self.get_azure_credential(self.AZURE_CLIENT_ID) return self._azure_credentials async def get_access_token(self) -> str: """Get Azure access token for API calls.""" try: - credential = self.get_azure_credentials() + credential = self.get_azure_credentials(self.AZURE_CLIENT_ID) token = credential.get_token(self.AZURE_COGNITIVE_SERVICES) return token.token except Exception as e: @@ -181,6 +181,42 @@ def _get_bool(self, name: str) -> bool: """ return name in os.environ and os.environ[name].lower() in ["true", "1"] + def get_cosmos_database_client(self): + """Get a Cosmos DB client for the configured database. + + Returns: + A Cosmos DB database client + """ + try: + if self._cosmos_client is None: + self._cosmos_client = CosmosClient( + self.COSMOSDB_ENDPOINT, credential=get_azure_credential(self.AZURE_CLIENT_ID) + ) + + if self._cosmos_database is None: + self._cosmos_database = self._cosmos_client.get_database_client( + self.COSMOSDB_DATABASE + ) + + return self._cosmos_database + except Exception as exc: + logging.error( + "Failed to create CosmosDB client: %s. CosmosDB is required for this application.", + exc, + ) + raise + + def create_kernel(self): + """Creates a new Semantic Kernel instance. + + Returns: + A new Semantic Kernel instance + """ + # Create a new kernel instance without manually configuring OpenAI services + # The agents will be created using Azure AI Agent Project pattern instead + kernel = Kernel() + return kernel + def get_ai_project_client(self): """Create and return an AIProjectClient for Azure AI Foundry using from_connection_string. @@ -191,7 +227,7 @@ def get_ai_project_client(self): return self._ai_project_client try: - credential = self.get_azure_credential() + credential = get_azure_credential(self.AZURE_CLIENT_ID) if credential is None: raise RuntimeError( "Unable to acquire Azure credentials; ensure Managed Identity is configured" diff --git a/src/backend/kernel_agents/planner_agent.py b/src/backend/kernel_agents/planner_agent.py index f8addabb5..452756228 100644 --- a/src/backend/kernel_agents/planner_agent.py +++ b/src/backend/kernel_agents/planner_agent.py @@ -539,7 +539,7 @@ def _generate_args(self, objective: str) -> any: if agent_name in self._available_agents: tools_list.append(tools) - tools_str = str(tools_list) + tools_str = tools_list # Return a dictionary with template variables return { diff --git a/src/backend/kernel_tools/generic_tools.py b/src/backend/kernel_tools/generic_tools.py index 320d381bb..7aa14b260 100644 --- a/src/backend/kernel_tools/generic_tools.py +++ b/src/backend/kernel_tools/generic_tools.py @@ -130,4 +130,4 @@ def generate_tools_json_doc(cls) -> str: tools_list.append(tool_entry) # Return the JSON string representation - return json.dumps(tools_list, ensure_ascii=False, indent=2) + return json.dumps(tools_list, ensure_ascii=False) diff --git a/src/backend/kernel_tools/hr_tools.py b/src/backend/kernel_tools/hr_tools.py index 151582710..76643e6f7 100644 --- a/src/backend/kernel_tools/hr_tools.py +++ b/src/backend/kernel_tools/hr_tools.py @@ -119,45 +119,45 @@ async def add_emergency_contact( f"{HrTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Process a leave request for an employee.") - async def process_leave_request( - employee_name: str, leave_type: str, start_date: str, end_date: str - ) -> str: - return ( - f"##### Leave Request Processed\n" - f"**Employee Name:** {employee_name}\n" - f"**Leave Type:** {leave_type}\n" - f"**Start Date:** {start_date}\n" - f"**End Date:** {end_date}\n\n" - f"Your leave request has been processed. " - f"Please ensure you have completed any necessary handover tasks before your leave.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Update company policies.") - async def update_policies(policy_name: str, policy_content: str) -> str: - return ( - f"##### Policy Updated\n" - f"**Policy Name:** {policy_name}\n\n" - f"The policy has been updated with the following content:\n\n" - f"{policy_content}\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function( - description="Conduct an exit interview for an employee leaving the company." - ) - async def conduct_exit_interview(employee_name: str) -> str: - return ( - f"##### Exit Interview Conducted\n" - f"**Employee Name:** {employee_name}\n\n" - f"The exit interview has been conducted. " - f"Thank you for your feedback and contributions to the company.\n" - f"{HrTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Process a leave request for an employee.") + # async def process_leave_request( + # employee_name: str, leave_type: str, start_date: str, end_date: str + # ) -> str: + # return ( + # f"##### Leave Request Processed\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Leave Type:** {leave_type}\n" + # f"**Start Date:** {start_date}\n" + # f"**End Date:** {end_date}\n\n" + # f"Your leave request has been processed. " + # f"Please ensure you have completed any necessary handover tasks before your leave.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Update company policies.") + # async def update_policies(policy_name: str, policy_content: str) -> str: + # return ( + # f"##### Policy Updated\n" + # f"**Policy Name:** {policy_name}\n\n" + # f"The policy has been updated with the following content:\n\n" + # f"{policy_content}\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function( + # description="Conduct an exit interview for an employee leaving the company." + # ) + # async def conduct_exit_interview(employee_name: str) -> str: + # return ( + # f"##### Exit Interview Conducted\n" + # f"**Employee Name:** {employee_name}\n\n" + # f"The exit interview has been conducted. " + # f"Thank you for your feedback and contributions to the company.\n" + # f"{HrTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Verify employment status for an employee.") @@ -169,39 +169,39 @@ async def verify_employment(employee_name: str) -> str: f"{HrTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Schedule a performance review for an employee.") - async def schedule_performance_review(employee_name: str, date: str) -> str: - return ( - f"##### Performance Review Scheduled\n" - f"**Employee Name:** {employee_name}\n" - f"**Date:** {date}\n\n" - f"Your performance review has been scheduled. " - f"Please prepare any necessary documents and be ready for the review.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Approve an expense claim for an employee.") - async def approve_expense_claim(employee_name: str, claim_amount: float) -> str: - return ( - f"##### Expense Claim Approved\n" - f"**Employee Name:** {employee_name}\n" - f"**Claim Amount:** ${claim_amount:.2f}\n\n" - f"Your expense claim has been approved. " - f"The amount will be reimbursed in your next payroll.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Send a company-wide announcement.") - async def send_company_announcement(subject: str, content: str) -> str: - return ( - f"##### Company Announcement\n" - f"**Subject:** {subject}\n\n" - f"{content}\n" - f"{HrTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Schedule a performance review for an employee.") + # async def schedule_performance_review(employee_name: str, date: str) -> str: + # return ( + # f"##### Performance Review Scheduled\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Date:** {date}\n\n" + # f"Your performance review has been scheduled. " + # f"Please prepare any necessary documents and be ready for the review.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Approve an expense claim for an employee.") + # async def approve_expense_claim(employee_name: str, claim_amount: float) -> str: + # return ( + # f"##### Expense Claim Approved\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Claim Amount:** ${claim_amount:.2f}\n\n" + # f"Your expense claim has been approved. " + # f"The amount will be reimbursed in your next payroll.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Send a company-wide announcement.") + # async def send_company_announcement(subject: str, content: str) -> str: + # return ( + # f"##### Company Announcement\n" + # f"**Subject:** {subject}\n\n" + # f"{content}\n" + # f"{HrTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Retrieve the employee directory.") @@ -252,39 +252,39 @@ async def organize_team_building_activity(activity_name: str, date: str) -> str: f"{HrTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Manage an employee transfer between departments.") - async def manage_employee_transfer(employee_name: str, new_department: str) -> str: - return ( - f"##### Employee Transfer\n" - f"**Employee Name:** {employee_name}\n" - f"**New Department:** {new_department}\n\n" - f"The transfer has been successfully processed. " - f"{employee_name} is now part of the {new_department} department.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Track attendance for an employee.") - async def track_employee_attendance(employee_name: str) -> str: - return ( - f"##### Attendance Tracked\n" - f"**Employee Name:** {employee_name}\n\n" - f"The attendance for {employee_name} has been successfully tracked.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Organize a health and wellness program.") - async def organize_wellness_program(program_name: str, date: str) -> str: - return ( - f"##### Health and Wellness Program Organized\n" - f"**Program Name:** {program_name}\n" - f"**Date:** {date}\n\n" - f"The health and wellness program has been successfully organized. " - f"Please join us on {date} for an informative and engaging session.\n" - f"{HrTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Manage an employee transfer between departments.") + # async def manage_employee_transfer(employee_name: str, new_department: str) -> str: + # return ( + # f"##### Employee Transfer\n" + # f"**Employee Name:** {employee_name}\n" + # f"**New Department:** {new_department}\n\n" + # f"The transfer has been successfully processed. " + # f"{employee_name} is now part of the {new_department} department.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Track attendance for an employee.") + # async def track_employee_attendance(employee_name: str) -> str: + # return ( + # f"##### Attendance Tracked\n" + # f"**Employee Name:** {employee_name}\n\n" + # f"The attendance for {employee_name} has been successfully tracked.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Organize a health and wellness program.") + # async def organize_wellness_program(program_name: str, date: str) -> str: + # return ( + # f"##### Health and Wellness Program Organized\n" + # f"**Program Name:** {program_name}\n" + # f"**Date:** {date}\n\n" + # f"The health and wellness program has been successfully organized. " + # f"Please join us on {date} for an informative and engaging session.\n" + # f"{HrTools.formatting_instructions}" + # ) @staticmethod @kernel_function( @@ -299,73 +299,73 @@ async def facilitate_remote_work_setup(employee_name: str) -> str: f"{HrTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Manage the retirement plan for an employee.") - async def manage_retirement_plan(employee_name: str) -> str: - return ( - f"##### Retirement Plan Managed\n" - f"**Employee Name:** {employee_name}\n\n" - f"The retirement plan for {employee_name} has been successfully managed.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Handle an overtime request for an employee.") - async def handle_overtime_request(employee_name: str, hours: float) -> str: - return ( - f"##### Overtime Request Handled\n" - f"**Employee Name:** {employee_name}\n" - f"**Hours:** {hours}\n\n" - f"The overtime request for {employee_name} has been successfully handled.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Issue a bonus to an employee.") - async def issue_bonus(employee_name: str, amount: float) -> str: - return ( - f"##### Bonus Issued\n" - f"**Employee Name:** {employee_name}\n" - f"**Amount:** ${amount:.2f}\n\n" - f"A bonus of ${amount:.2f} has been issued to {employee_name}.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Schedule a wellness check for an employee.") - async def schedule_wellness_check(employee_name: str, date: str) -> str: - return ( - f"##### Wellness Check Scheduled\n" - f"**Employee Name:** {employee_name}\n" - f"**Date:** {date}\n\n" - f"A wellness check has been scheduled for {employee_name} on {date}.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Handle a suggestion made by an employee.") - async def handle_employee_suggestion(employee_name: str, suggestion: str) -> str: - return ( - f"##### Employee Suggestion Handled\n" - f"**Employee Name:** {employee_name}\n" - f"**Suggestion:** {suggestion}\n\n" - f"The suggestion from {employee_name} has been successfully handled.\n" - f"{HrTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Update privileges for an employee.") - async def update_employee_privileges( - employee_name: str, privilege: str, status: str - ) -> str: - return ( - f"##### Employee Privileges Updated\n" - f"**Employee Name:** {employee_name}\n" - f"**Privilege:** {privilege}\n" - f"**Status:** {status}\n\n" - f"The privileges for {employee_name} have been successfully updated.\n" - f"{HrTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Manage the retirement plan for an employee.") + # async def manage_retirement_plan(employee_name: str) -> str: + # return ( + # f"##### Retirement Plan Managed\n" + # f"**Employee Name:** {employee_name}\n\n" + # f"The retirement plan for {employee_name} has been successfully managed.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Handle an overtime request for an employee.") + # async def handle_overtime_request(employee_name: str, hours: float) -> str: + # return ( + # f"##### Overtime Request Handled\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Hours:** {hours}\n\n" + # f"The overtime request for {employee_name} has been successfully handled.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Issue a bonus to an employee.") + # async def issue_bonus(employee_name: str, amount: float) -> str: + # return ( + # f"##### Bonus Issued\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Amount:** ${amount:.2f}\n\n" + # f"A bonus of ${amount:.2f} has been issued to {employee_name}.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Schedule a wellness check for an employee.") + # async def schedule_wellness_check(employee_name: str, date: str) -> str: + # return ( + # f"##### Wellness Check Scheduled\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Date:** {date}\n\n" + # f"A wellness check has been scheduled for {employee_name} on {date}.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Handle a suggestion made by an employee.") + # async def handle_employee_suggestion(employee_name: str, suggestion: str) -> str: + # return ( + # f"##### Employee Suggestion Handled\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Suggestion:** {suggestion}\n\n" + # f"The suggestion from {employee_name} has been successfully handled.\n" + # f"{HrTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Update privileges for an employee.") + # async def update_employee_privileges( + # employee_name: str, privilege: str, status: str + # ) -> str: + # return ( + # f"##### Employee Privileges Updated\n" + # f"**Employee Name:** {employee_name}\n" + # f"**Privilege:** {privilege}\n" + # f"**Status:** {status}\n\n" + # f"The privileges for {employee_name} have been successfully updated.\n" + # f"{HrTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Send a welcome email to an address.") @@ -485,4 +485,4 @@ def generate_tools_json_doc(cls) -> str: tools_list.append(tool_entry) # Return the JSON string representation - return json.dumps(tools_list, ensure_ascii=False, indent=2) + return json.dumps(tools_list, ensure_ascii=False) diff --git a/src/backend/kernel_tools/marketing_tools.py b/src/backend/kernel_tools/marketing_tools.py index fdbf4ed30..250191faa 100644 --- a/src/backend/kernel_tools/marketing_tools.py +++ b/src/backend/kernel_tools/marketing_tools.py @@ -37,24 +37,24 @@ async def generate_social_posts(campaign_name: str, platforms: List[str]) -> str async def plan_advertising_budget(campaign_name: str, total_budget: float) -> str: return f"Advertising budget planned for campaign '{campaign_name}' with a total budget of ${total_budget:.2f}." - @staticmethod - @kernel_function(description="Conduct a customer survey on a specific topic.") - async def conduct_customer_survey(survey_topic: str, target_group: str) -> str: - return ( - f"Customer survey on '{survey_topic}' conducted targeting '{target_group}'." - ) + # @staticmethod + # @kernel_function(description="Conduct a customer survey on a specific topic.") + # async def conduct_customer_survey(survey_topic: str, target_group: str) -> str: + # return ( + # f"Customer survey on '{survey_topic}' conducted targeting '{target_group}'." + # ) @staticmethod @kernel_function(description="Perform a competitor analysis.") async def perform_competitor_analysis(competitor_name: str) -> str: return f"Competitor analysis performed on '{competitor_name}'." - @staticmethod - @kernel_function(description="Schedule a marketing event.") - async def schedule_marketing_event( - event_name: str, date: str, location: str - ) -> str: - return f"Marketing event '{event_name}' scheduled on {date} at {location}." + # @staticmethod + # @kernel_function(description="Schedule a marketing event.") + # async def schedule_marketing_event( + # event_name: str, date: str, location: str + # ) -> str: + # return f"Marketing event '{event_name}' scheduled on {date} at {location}." @staticmethod @kernel_function(description="Design promotional material for a campaign.") @@ -68,30 +68,30 @@ async def design_promotional_material( async def manage_email_marketing(campaign_name: str, email_list_size: int) -> str: return f"Email marketing managed for campaign '{campaign_name}' targeting {email_list_size} recipients." - @staticmethod - @kernel_function(description="Track the performance of a campaign.") - async def track_campaign_performance(campaign_name: str) -> str: - return f"Performance of campaign '{campaign_name}' tracked." + # @staticmethod + # @kernel_function(description="Track the performance of a campaign.") + # async def track_campaign_performance(campaign_name: str) -> str: + # return f"Performance of campaign '{campaign_name}' tracked." @staticmethod @kernel_function(description="Coordinate a campaign with the sales team.") async def coordinate_with_sales_team(campaign_name: str) -> str: return f"Campaign '{campaign_name}' coordinated with the sales team." - @staticmethod - @kernel_function(description="Develop a brand strategy.") - async def develop_brand_strategy(brand_name: str) -> str: - return f"Brand strategy developed for '{brand_name}'." + # @staticmethod + # @kernel_function(description="Develop a brand strategy.") + # async def develop_brand_strategy(brand_name: str) -> str: + # return f"Brand strategy developed for '{brand_name}'." - @staticmethod - @kernel_function(description="Create a content calendar for a specific month.") - async def create_content_calendar(month: str) -> str: - return f"Content calendar for '{month}' created." + # @staticmethod + # @kernel_function(description="Create a content calendar for a specific month.") + # async def create_content_calendar(month: str) -> str: + # return f"Content calendar for '{month}' created." - @staticmethod - @kernel_function(description="Update content on a specific website page.") - async def update_website_content(page_name: str) -> str: - return f"Website content on page '{page_name}' updated." + # @staticmethod + # @kernel_function(description="Update content on a specific website page.") + # async def update_website_content(page_name: str) -> str: + # return f"Website content on page '{page_name}' updated." @staticmethod @kernel_function(description="Plan a product launch.") @@ -105,27 +105,27 @@ async def plan_product_launch(product_name: str, launch_date: str) -> str: async def generate_press_release(key_information_for_press_release: str) -> str: return f"Look through the conversation history. Identify the content. Now you must generate a press release based on this content {key_information_for_press_release}. Make it approximately 2 paragraphs." - @staticmethod - @kernel_function(description="Conduct market research on a specific topic.") - async def conduct_market_research(research_topic: str) -> str: - return f"Market research conducted on '{research_topic}'." + # @staticmethod + # @kernel_function(description="Conduct market research on a specific topic.") + # async def conduct_market_research(research_topic: str) -> str: + # return f"Market research conducted on '{research_topic}'." - @staticmethod - @kernel_function(description="Handle customer feedback.") - async def handle_customer_feedback(feedback_details: str) -> str: - return f"Customer feedback handled: {feedback_details}." + # @staticmethod + # @kernel_function(description="Handle customer feedback.") + # async def handle_customer_feedback(feedback_details: str) -> str: + # return f"Customer feedback handled: {feedback_details}." @staticmethod @kernel_function(description="Generate a marketing report for a campaign.") async def generate_marketing_report(campaign_name: str) -> str: return f"Marketing report generated for campaign '{campaign_name}'." - @staticmethod - @kernel_function(description="Manage a social media account.") - async def manage_social_media_account(platform: str, account_name: str) -> str: - return ( - f"Social media account '{account_name}' on platform '{platform}' managed." - ) + # @staticmethod + # @kernel_function(description="Manage a social media account.") + # async def manage_social_media_account(platform: str, account_name: str) -> str: + # return ( + # f"Social media account '{account_name}' on platform '{platform}' managed." + # ) @staticmethod @kernel_function(description="Create a video advertisement.") @@ -134,15 +134,15 @@ async def create_video_ad(content_title: str, platform: str) -> str: f"Video advertisement '{content_title}' created for platform '{platform}'." ) - @staticmethod - @kernel_function(description="Conduct a focus group study.") - async def conduct_focus_group(study_topic: str, participants: int) -> str: - return f"Focus group study on '{study_topic}' conducted with {participants} participants." + # @staticmethod + # @kernel_function(description="Conduct a focus group study.") + # async def conduct_focus_group(study_topic: str, participants: int) -> str: + # return f"Focus group study on '{study_topic}' conducted with {participants} participants." - @staticmethod - @kernel_function(description="Update brand guidelines.") - async def update_brand_guidelines(brand_name: str, guidelines: str) -> str: - return f"Brand guidelines for '{brand_name}' updated." + # @staticmethod + # @kernel_function(description="Update brand guidelines.") + # async def update_brand_guidelines(brand_name: str, guidelines: str) -> str: + # return f"Brand guidelines for '{brand_name}' updated." @staticmethod @kernel_function(description="Handle collaboration with an influencer.") @@ -151,30 +151,30 @@ async def handle_influencer_collaboration( ) -> str: return f"Collaboration with influencer '{influencer_name}' for campaign '{campaign_name}' handled." - @staticmethod - @kernel_function(description="Analyze customer behavior in a specific segment.") - async def analyze_customer_behavior(segment: str) -> str: - return f"Customer behavior in segment '{segment}' analyzed." + # @staticmethod + # @kernel_function(description="Analyze customer behavior in a specific segment.") + # async def analyze_customer_behavior(segment: str) -> str: + # return f"Customer behavior in segment '{segment}' analyzed." - @staticmethod - @kernel_function(description="Manage a customer loyalty program.") - async def manage_loyalty_program(program_name: str, members: int) -> str: - return f"Loyalty program '{program_name}' managed with {members} members." + # @staticmethod + # @kernel_function(description="Manage a customer loyalty program.") + # async def manage_loyalty_program(program_name: str, members: int) -> str: + # return f"Loyalty program '{program_name}' managed with {members} members." @staticmethod @kernel_function(description="Develop a content strategy.") async def develop_content_strategy(strategy_name: str) -> str: return f"Content strategy '{strategy_name}' developed." - @staticmethod - @kernel_function(description="Create an infographic.") - async def create_infographic(content_title: str) -> str: - return f"Infographic '{content_title}' created." + # @staticmethod + # @kernel_function(description="Create an infographic.") + # async def create_infographic(content_title: str) -> str: + # return f"Infographic '{content_title}' created." - @staticmethod - @kernel_function(description="Schedule a webinar.") - async def schedule_webinar(webinar_title: str, date: str, platform: str) -> str: - return f"Webinar '{webinar_title}' scheduled on {date} via {platform}." + # @staticmethod + # @kernel_function(description="Schedule a webinar.") + # async def schedule_webinar(webinar_title: str, date: str, platform: str) -> str: + # return f"Webinar '{webinar_title}' scheduled on {date} via {platform}." @staticmethod @kernel_function(description="Manage online reputation for a brand.") @@ -186,10 +186,10 @@ async def manage_online_reputation(brand_name: str) -> str: async def run_email_ab_testing(campaign_name: str) -> str: return f"A/B testing for email campaign '{campaign_name}' run." - @staticmethod - @kernel_function(description="Create a podcast episode.") - async def create_podcast_episode(series_name: str, episode_title: str) -> str: - return f"Podcast episode '{episode_title}' for series '{series_name}' created." + # @staticmethod + # @kernel_function(description="Create a podcast episode.") + # async def create_podcast_episode(series_name: str, episode_title: str) -> str: + # return f"Podcast episode '{episode_title}' for series '{series_name}' created." @staticmethod @kernel_function(description="Manage an affiliate marketing program.") @@ -198,20 +198,20 @@ async def manage_affiliate_program(program_name: str, affiliates: int) -> str: f"Affiliate program '{program_name}' managed with {affiliates} affiliates." ) - @staticmethod - @kernel_function(description="Generate lead magnets.") - async def generate_lead_magnets(content_title: str) -> str: - return f"Lead magnet '{content_title}' generated." + # @staticmethod + # @kernel_function(description="Generate lead magnets.") + # async def generate_lead_magnets(content_title: str) -> str: + # return f"Lead magnet '{content_title}' generated." - @staticmethod - @kernel_function(description="Organize participation in a trade show.") - async def organize_trade_show(booth_number: str, event_name: str) -> str: - return f"Trade show '{event_name}' organized at booth number '{booth_number}'." + # @staticmethod + # @kernel_function(description="Organize participation in a trade show.") + # async def organize_trade_show(booth_number: str, event_name: str) -> str: + # return f"Trade show '{event_name}' organized at booth number '{booth_number}'." - @staticmethod - @kernel_function(description="Manage a customer retention program.") - async def manage_retention_program(program_name: str) -> str: - return f"Customer retention program '{program_name}' managed." + # @staticmethod + # @kernel_function(description="Manage a customer retention program.") + # async def manage_retention_program(program_name: str) -> str: + # return f"Customer retention program '{program_name}' managed." @staticmethod @kernel_function(description="Run a pay-per-click (PPC) campaign.") @@ -223,25 +223,25 @@ async def run_ppc_campaign(campaign_name: str, budget: float) -> str: async def create_case_study(case_title: str, client_name: str) -> str: return f"Case study '{case_title}' for client '{client_name}' created." - @staticmethod - @kernel_function(description="Generate lead nurturing emails.") - async def generate_lead_nurturing_emails(sequence_name: str, steps: int) -> str: - return f"Lead nurturing email sequence '{sequence_name}' generated with {steps} steps." + # @staticmethod + # @kernel_function(description="Generate lead nurturing emails.") + # async def generate_lead_nurturing_emails(sequence_name: str, steps: int) -> str: + # return f"Lead nurturing email sequence '{sequence_name}' generated with {steps} steps." - @staticmethod - @kernel_function(description="Manage crisis communication.") - async def manage_crisis_communication(crisis_situation: str) -> str: - return f"Crisis communication managed for situation '{crisis_situation}'." + # @staticmethod + # @kernel_function(description="Manage crisis communication.") + # async def manage_crisis_communication(crisis_situation: str) -> str: + # return f"Crisis communication managed for situation '{crisis_situation}'." - @staticmethod - @kernel_function(description="Create interactive content.") - async def create_interactive_content(content_title: str) -> str: - return f"Interactive content '{content_title}' created." + # @staticmethod + # @kernel_function(description="Create interactive content.") + # async def create_interactive_content(content_title: str) -> str: + # return f"Interactive content '{content_title}' created." - @staticmethod - @kernel_function(description="Handle media relations.") - async def handle_media_relations(media_outlet: str) -> str: - return f"Media relations handled with '{media_outlet}'." + # @staticmethod + # @kernel_function(description="Handle media relations.") + # async def handle_media_relations(media_outlet: str) -> str: + # return f"Media relations handled with '{media_outlet}'." @staticmethod @kernel_function(description="Create a testimonial video.") @@ -253,10 +253,10 @@ async def create_testimonial_video(client_name: str) -> str: async def manage_event_sponsorship(event_name: str, sponsor_name: str) -> str: return f"Event sponsorship for '{event_name}' managed with sponsor '{sponsor_name}'." - @staticmethod - @kernel_function(description="Optimize a specific stage of the conversion funnel.") - async def optimize_conversion_funnel(stage: str) -> str: - return f"Conversion funnel stage '{stage}' optimized." + # @staticmethod + # @kernel_function(description="Optimize a specific stage of the conversion funnel.") + # async def optimize_conversion_funnel(stage: str) -> str: + # return f"Conversion funnel stage '{stage}' optimized." # ToDo: Seems to be a bug in SK when processing functions with list parameters @staticmethod @@ -360,7 +360,7 @@ def generate_tools_json_doc(cls) -> str: tools_list.append(tool_entry) # Return the JSON string representation - return json.dumps(tools_list, ensure_ascii=False, indent=2) + return json.dumps(tools_list, ensure_ascii=False) # This function does NOT have the kernel_function annotation # because it's meant for introspection rather than being exposed as a tool diff --git a/src/backend/kernel_tools/procurement_tools.py b/src/backend/kernel_tools/procurement_tools.py index 4955e5100..9b78e7e76 100644 --- a/src/backend/kernel_tools/procurement_tools.py +++ b/src/backend/kernel_tools/procurement_tools.py @@ -49,60 +49,60 @@ async def check_inventory(item_name: str) -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Process a purchase order.") - async def process_purchase_order(po_number: str) -> str: - return ( - f"##### Purchase Order Processed\n" - f"**PO Number:** {po_number}\n\n" - f"Purchase Order {po_number} has been processed.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Initiate contract negotiation with a vendor.") - async def initiate_contract_negotiation( - vendor_name: str, contract_details: str - ) -> str: - return ( - f"##### Contract Negotiation Initiated\n" - f"**Vendor:** {vendor_name}\n" - f"**Contract Details:** {contract_details}\n\n" - f"Contract negotiation initiated with {vendor_name}: {contract_details}\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Approve an invoice for payment.") - async def approve_invoice(invoice_number: str) -> str: - return ( - f"##### Invoice Approved\n" - f"**Invoice Number:** {invoice_number}\n\n" - f"Invoice {invoice_number} approved for payment.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Track the status of an order.") - async def track_order(order_number: str) -> str: - return ( - f"##### Order Tracking\n" - f"**Order Number:** {order_number}\n" - f"**Status:** In Transit\n\n" - f"Order {order_number} is currently in transit.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Manage relationships with vendors.") - async def manage_vendor_relationship(vendor_name: str, action: str) -> str: - return ( - f"##### Vendor Relationship Update\n" - f"**Vendor:** {vendor_name}\n" - f"**Action:** {action}\n\n" - f"Vendor relationship with {vendor_name} has been {action}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Process a purchase order.") + # async def process_purchase_order(po_number: str) -> str: + # return ( + # f"##### Purchase Order Processed\n" + # f"**PO Number:** {po_number}\n\n" + # f"Purchase Order {po_number} has been processed.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Initiate contract negotiation with a vendor.") + # async def initiate_contract_negotiation( + # vendor_name: str, contract_details: str + # ) -> str: + # return ( + # f"##### Contract Negotiation Initiated\n" + # f"**Vendor:** {vendor_name}\n" + # f"**Contract Details:** {contract_details}\n\n" + # f"Contract negotiation initiated with {vendor_name}: {contract_details}\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Approve an invoice for payment.") + # async def approve_invoice(invoice_number: str) -> str: + # return ( + # f"##### Invoice Approved\n" + # f"**Invoice Number:** {invoice_number}\n\n" + # f"Invoice {invoice_number} approved for payment.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Track the status of an order.") + # async def track_order(order_number: str) -> str: + # return ( + # f"##### Order Tracking\n" + # f"**Order Number:** {order_number}\n" + # f"**Status:** In Transit\n\n" + # f"Order {order_number} is currently in transit.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Manage relationships with vendors.") + # async def manage_vendor_relationship(vendor_name: str, action: str) -> str: + # return ( + # f"##### Vendor Relationship Update\n" + # f"**Vendor:** {vendor_name}\n" + # f"**Action:** {action}\n\n" + # f"Vendor relationship with {vendor_name} has been {action}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Update a procurement policy.") @@ -114,25 +114,25 @@ async def update_procurement_policy(policy_name: str, policy_content: str) -> st f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Generate a procurement report.") - async def generate_procurement_report(report_type: str) -> str: - return ( - f"##### Procurement Report Generated\n" - f"**Report Type:** {report_type}\n\n" - f"Generated {report_type} procurement report.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Generate a procurement report.") + # async def generate_procurement_report(report_type: str) -> str: + # return ( + # f"##### Procurement Report Generated\n" + # f"**Report Type:** {report_type}\n\n" + # f"Generated {report_type} procurement report.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) - @staticmethod - @kernel_function(description="Evaluate the performance of a supplier.") - async def evaluate_supplier_performance(supplier_name: str) -> str: - return ( - f"##### Supplier Performance Evaluation\n" - f"**Supplier:** {supplier_name}\n\n" - f"Performance evaluation for supplier {supplier_name} completed.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Evaluate the performance of a supplier.") + # async def evaluate_supplier_performance(supplier_name: str) -> str: + # return ( + # f"##### Supplier Performance Evaluation\n" + # f"**Supplier:** {supplier_name}\n\n" + # f"Performance evaluation for supplier {supplier_name} completed.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Handle the return of procured items.") @@ -168,59 +168,59 @@ async def request_quote(item_name: str, quantity: int) -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Recommend sourcing options for an item.") - async def recommend_sourcing_options(item_name: str) -> str: - return ( - f"##### Sourcing Options\n" - f"**Item:** {item_name}\n\n" - f"Sourcing options for {item_name} have been provided.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function( - description="Update the asset register with new or disposed assets." - ) - async def update_asset_register(asset_name: str, asset_details: str) -> str: - return ( - f"##### Asset Register Updated\n" - f"**Asset:** {asset_name}\n" - f"**Details:** {asset_details}\n\n" - f"Asset register updated for {asset_name}: {asset_details}\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Manage leasing agreements for assets.") - async def manage_leasing_agreements(agreement_details: str) -> str: - return ( - f"##### Leasing Agreement Managed\n" - f"**Agreement Details:** {agreement_details}\n\n" - f"Leasing agreement processed: {agreement_details}\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Conduct market research for procurement purposes.") - async def conduct_market_research(category: str) -> str: - return ( - f"##### Market Research Conducted\n" - f"**Category:** {category}\n\n" - f"Market research conducted for category: {category}\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Schedule maintenance for equipment.") - async def schedule_maintenance(equipment_name: str, maintenance_date: str) -> str: - return ( - f"##### Maintenance Scheduled\n" - f"**Equipment:** {equipment_name}\n" - f"**Date:** {maintenance_date}\n\n" - f"Scheduled maintenance for {equipment_name} on {maintenance_date}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Recommend sourcing options for an item.") + # async def recommend_sourcing_options(item_name: str) -> str: + # return ( + # f"##### Sourcing Options\n" + # f"**Item:** {item_name}\n\n" + # f"Sourcing options for {item_name} have been provided.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function( + # description="Update the asset register with new or disposed assets." + # ) + # async def update_asset_register(asset_name: str, asset_details: str) -> str: + # return ( + # f"##### Asset Register Updated\n" + # f"**Asset:** {asset_name}\n" + # f"**Details:** {asset_details}\n\n" + # f"Asset register updated for {asset_name}: {asset_details}\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Manage leasing agreements for assets.") + # async def manage_leasing_agreements(agreement_details: str) -> str: + # return ( + # f"##### Leasing Agreement Managed\n" + # f"**Agreement Details:** {agreement_details}\n\n" + # f"Leasing agreement processed: {agreement_details}\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Conduct market research for procurement purposes.") + # async def conduct_market_research(category: str) -> str: + # return ( + # f"##### Market Research Conducted\n" + # f"**Category:** {category}\n\n" + # f"Market research conducted for category: {category}\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Schedule maintenance for equipment.") + # async def schedule_maintenance(equipment_name: str, maintenance_date: str) -> str: + # return ( + # f"##### Maintenance Scheduled\n" + # f"**Equipment:** {equipment_name}\n" + # f"**Date:** {maintenance_date}\n\n" + # f"Scheduled maintenance for {equipment_name} on {maintenance_date}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Conduct an inventory audit.") @@ -231,61 +231,61 @@ async def audit_inventory() -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Approve a procurement budget.") - async def approve_budget(budget_id: str, amount: float) -> str: - return ( - f"##### Budget Approved\n" - f"**Budget ID:** {budget_id}\n" - f"**Amount:** ${amount:.2f}\n\n" - f"Approved budget ID {budget_id} for amount ${amount:.2f}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Manage warranties for procured items.") - async def manage_warranty(item_name: str, warranty_period: str) -> str: - return ( - f"##### Warranty Management\n" - f"**Item:** {item_name}\n" - f"**Warranty Period:** {warranty_period}\n\n" - f"Warranty for {item_name} managed for period {warranty_period}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function( - description="Handle customs clearance for international shipments." - ) - async def handle_customs_clearance(shipment_id: str) -> str: - return ( - f"##### Customs Clearance\n" - f"**Shipment ID:** {shipment_id}\n\n" - f"Customs clearance for shipment ID {shipment_id} handled.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Negotiate a discount with a vendor.") - async def negotiate_discount(vendor_name: str, discount_percentage: float) -> str: - return ( - f"##### Discount Negotiated\n" - f"**Vendor:** {vendor_name}\n" - f"**Discount:** {discount_percentage}%\n\n" - f"Negotiated a {discount_percentage}% discount with vendor {vendor_name}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Register a new vendor.") - async def register_new_vendor(vendor_name: str, vendor_details: str) -> str: - return ( - f"##### New Vendor Registered\n" - f"**Vendor:** {vendor_name}\n" - f"**Details:** {vendor_details}\n\n" - f"New vendor {vendor_name} registered with details: {vendor_details}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Approve a procurement budget.") + # async def approve_budget(budget_id: str, amount: float) -> str: + # return ( + # f"##### Budget Approved\n" + # f"**Budget ID:** {budget_id}\n" + # f"**Amount:** ${amount:.2f}\n\n" + # f"Approved budget ID {budget_id} for amount ${amount:.2f}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Manage warranties for procured items.") + # async def manage_warranty(item_name: str, warranty_period: str) -> str: + # return ( + # f"##### Warranty Management\n" + # f"**Item:** {item_name}\n" + # f"**Warranty Period:** {warranty_period}\n\n" + # f"Warranty for {item_name} managed for period {warranty_period}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function( + # description="Handle customs clearance for international shipments." + # ) + # async def handle_customs_clearance(shipment_id: str) -> str: + # return ( + # f"##### Customs Clearance\n" + # f"**Shipment ID:** {shipment_id}\n\n" + # f"Customs clearance for shipment ID {shipment_id} handled.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Negotiate a discount with a vendor.") + # async def negotiate_discount(vendor_name: str, discount_percentage: float) -> str: + # return ( + # f"##### Discount Negotiated\n" + # f"**Vendor:** {vendor_name}\n" + # f"**Discount:** {discount_percentage}%\n\n" + # f"Negotiated a {discount_percentage}% discount with vendor {vendor_name}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Register a new vendor.") + # async def register_new_vendor(vendor_name: str, vendor_details: str) -> str: + # return ( + # f"##### New Vendor Registered\n" + # f"**Vendor:** {vendor_name}\n" + # f"**Details:** {vendor_details}\n\n" + # f"New vendor {vendor_name} registered with details: {vendor_details}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Decommission an asset.") @@ -297,27 +297,27 @@ async def decommission_asset(asset_name: str) -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Schedule a training session for procurement staff.") - async def schedule_training(session_name: str, date: str) -> str: - return ( - f"##### Training Session Scheduled\n" - f"**Session:** {session_name}\n" - f"**Date:** {date}\n\n" - f"Training session '{session_name}' scheduled on {date}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Schedule a training session for procurement staff.") + # async def schedule_training(session_name: str, date: str) -> str: + # return ( + # f"##### Training Session Scheduled\n" + # f"**Session:** {session_name}\n" + # f"**Date:** {date}\n\n" + # f"Training session '{session_name}' scheduled on {date}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) - @staticmethod - @kernel_function(description="Update the rating of a vendor.") - async def update_vendor_rating(vendor_name: str, rating: float) -> str: - return ( - f"##### Vendor Rating Updated\n" - f"**Vendor:** {vendor_name}\n" - f"**Rating:** {rating}\n\n" - f"Vendor {vendor_name} rating updated to {rating}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Update the rating of a vendor.") + # async def update_vendor_rating(vendor_name: str, rating: float) -> str: + # return ( + # f"##### Vendor Rating Updated\n" + # f"**Vendor:** {vendor_name}\n" + # f"**Rating:** {rating}\n\n" + # f"Vendor {vendor_name} rating updated to {rating}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Handle the recall of a procured item.") @@ -330,58 +330,58 @@ async def handle_recall(item_name: str, recall_reason: str) -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Request samples of an item.") - async def request_samples(item_name: str, quantity: int) -> str: - return ( - f"##### Samples Requested\n" - f"**Item:** {item_name}\n" - f"**Quantity:** {quantity}\n\n" - f"Requested {quantity} samples of {item_name}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Manage subscriptions to services.") - async def manage_subscription(service_name: str, action: str) -> str: - return ( - f"##### Subscription Management\n" - f"**Service:** {service_name}\n" - f"**Action:** {action}\n\n" - f"Subscription to {service_name} has been {action}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Verify the certification status of a supplier.") - async def verify_supplier_certification(supplier_name: str) -> str: - return ( - f"##### Supplier Certification Verified\n" - f"**Supplier:** {supplier_name}\n\n" - f"Certification status of supplier {supplier_name} verified.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Conduct an audit of a supplier.") - async def conduct_supplier_audit(supplier_name: str) -> str: - return ( - f"##### Supplier Audit Conducted\n" - f"**Supplier:** {supplier_name}\n\n" - f"Audit of supplier {supplier_name} conducted.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Manage import licenses for items.") - async def manage_import_licenses(item_name: str, license_details: str) -> str: - return ( - f"##### Import License Management\n" - f"**Item:** {item_name}\n" - f"**License Details:** {license_details}\n\n" - f"Import license for {item_name} managed: {license_details}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Request samples of an item.") + # async def request_samples(item_name: str, quantity: int) -> str: + # return ( + # f"##### Samples Requested\n" + # f"**Item:** {item_name}\n" + # f"**Quantity:** {quantity}\n\n" + # f"Requested {quantity} samples of {item_name}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Manage subscriptions to services.") + # async def manage_subscription(service_name: str, action: str) -> str: + # return ( + # f"##### Subscription Management\n" + # f"**Service:** {service_name}\n" + # f"**Action:** {action}\n\n" + # f"Subscription to {service_name} has been {action}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Verify the certification status of a supplier.") + # async def verify_supplier_certification(supplier_name: str) -> str: + # return ( + # f"##### Supplier Certification Verified\n" + # f"**Supplier:** {supplier_name}\n\n" + # f"Certification status of supplier {supplier_name} verified.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Conduct an audit of a supplier.") + # async def conduct_supplier_audit(supplier_name: str) -> str: + # return ( + # f"##### Supplier Audit Conducted\n" + # f"**Supplier:** {supplier_name}\n\n" + # f"Audit of supplier {supplier_name} conducted.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Manage import licenses for items.") + # async def manage_import_licenses(item_name: str, license_details: str) -> str: + # return ( + # f"##### Import License Management\n" + # f"**Item:** {item_name}\n" + # f"**License Details:** {license_details}\n\n" + # f"Import license for {item_name} managed: {license_details}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Conduct a cost analysis for an item.") @@ -405,15 +405,15 @@ async def evaluate_risk_factors(item_name: str) -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Manage green procurement policy.") - async def manage_green_procurement_policy(policy_details: str) -> str: - return ( - f"##### Green Procurement Policy Management\n" - f"**Details:** {policy_details}\n\n" - f"Green procurement policy managed: {policy_details}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Manage green procurement policy.") + # async def manage_green_procurement_policy(policy_details: str) -> str: + # return ( + # f"##### Green Procurement Policy Management\n" + # f"**Details:** {policy_details}\n\n" + # f"Green procurement policy managed: {policy_details}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Update the supplier database with new information.") @@ -426,49 +426,49 @@ async def update_supplier_database(supplier_name: str, supplier_info: str) -> st f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Handle dispute resolution with a vendor.") - async def handle_dispute_resolution(vendor_name: str, issue: str) -> str: - return ( - f"##### Dispute Resolution\n" - f"**Vendor:** {vendor_name}\n" - f"**Issue:** {issue}\n\n" - f"Dispute with vendor {vendor_name} over issue '{issue}' resolved.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Assess compliance of an item with standards.") - async def assess_compliance(item_name: str, compliance_standards: str) -> str: - return ( - f"##### Compliance Assessment\n" - f"**Item:** {item_name}\n" - f"**Standards:** {compliance_standards}\n\n" - f"Compliance of {item_name} with standards '{compliance_standards}' assessed.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Manage reverse logistics for returning items.") - async def manage_reverse_logistics(item_name: str, quantity: int) -> str: - return ( - f"##### Reverse Logistics Management\n" - f"**Item:** {item_name}\n" - f"**Quantity:** {quantity}\n\n" - f"Reverse logistics managed for {quantity} units of {item_name}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Verify delivery status of an item.") - async def verify_delivery(item_name: str, delivery_status: str) -> str: - return ( - f"##### Delivery Status Verification\n" - f"**Item:** {item_name}\n" - f"**Status:** {delivery_status}\n\n" - f"Delivery status of {item_name} verified as {delivery_status}.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Handle dispute resolution with a vendor.") + # async def handle_dispute_resolution(vendor_name: str, issue: str) -> str: + # return ( + # f"##### Dispute Resolution\n" + # f"**Vendor:** {vendor_name}\n" + # f"**Issue:** {issue}\n\n" + # f"Dispute with vendor {vendor_name} over issue '{issue}' resolved.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Assess compliance of an item with standards.") + # async def assess_compliance(item_name: str, compliance_standards: str) -> str: + # return ( + # f"##### Compliance Assessment\n" + # f"**Item:** {item_name}\n" + # f"**Standards:** {compliance_standards}\n\n" + # f"Compliance of {item_name} with standards '{compliance_standards}' assessed.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Manage reverse logistics for returning items.") + # async def manage_reverse_logistics(item_name: str, quantity: int) -> str: + # return ( + # f"##### Reverse Logistics Management\n" + # f"**Item:** {item_name}\n" + # f"**Quantity:** {quantity}\n\n" + # f"Reverse logistics managed for {quantity} units of {item_name}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Verify delivery status of an item.") + # async def verify_delivery(item_name: str, delivery_status: str) -> str: + # return ( + # f"##### Delivery Status Verification\n" + # f"**Item:** {item_name}\n" + # f"**Status:** {delivery_status}\n\n" + # f"Delivery status of {item_name} verified as {delivery_status}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="assess procurement risk assessment.") @@ -480,37 +480,37 @@ async def assess_procurement_risk(risk_details: str) -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Manage supplier contract actions.") - async def manage_supplier_contract(supplier_name: str, contract_action: str) -> str: - return ( - f"##### Supplier Contract Management\n" - f"**Supplier:** {supplier_name}\n" - f"**Action:** {contract_action}\n\n" - f"Supplier contract with {supplier_name} has been {contract_action}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Allocate budget to a department.") - async def allocate_budget(department_name: str, budget_amount: float) -> str: - return ( - f"##### Budget Allocation\n" - f"**Department:** {department_name}\n" - f"**Amount:** ${budget_amount:.2f}\n\n" - f"Allocated budget of ${budget_amount:.2f} to {department_name}.\n" - f"{ProcurementTools.formatting_instructions}" - ) - - @staticmethod - @kernel_function(description="Track procurement metrics.") - async def track_procurement_metrics(metric_name: str) -> str: - return ( - f"##### Procurement Metrics Tracking\n" - f"**Metric:** {metric_name}\n\n" - f"Procurement metric '{metric_name}' tracked.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Manage supplier contract actions.") + # async def manage_supplier_contract(supplier_name: str, contract_action: str) -> str: + # return ( + # f"##### Supplier Contract Management\n" + # f"**Supplier:** {supplier_name}\n" + # f"**Action:** {contract_action}\n\n" + # f"Supplier contract with {supplier_name} has been {contract_action}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Allocate budget to a department.") + # async def allocate_budget(department_name: str, budget_amount: float) -> str: + # return ( + # f"##### Budget Allocation\n" + # f"**Department:** {department_name}\n" + # f"**Amount:** ${budget_amount:.2f}\n\n" + # f"Allocated budget of ${budget_amount:.2f} to {department_name}.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) + + # @staticmethod + # @kernel_function(description="Track procurement metrics.") + # async def track_procurement_metrics(metric_name: str) -> str: + # return ( + # f"##### Procurement Metrics Tracking\n" + # f"**Metric:** {metric_name}\n\n" + # f"Procurement metric '{metric_name}' tracked.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function(description="Manage inventory levels for an item.") @@ -523,15 +523,15 @@ async def manage_inventory_levels(item_name: str, action: str) -> str: f"{ProcurementTools.formatting_instructions}" ) - @staticmethod - @kernel_function(description="Conduct a survey of a supplier.") - async def conduct_supplier_survey(supplier_name: str) -> str: - return ( - f"##### Supplier Survey Conducted\n" - f"**Supplier:** {supplier_name}\n\n" - f"Survey of supplier {supplier_name} conducted.\n" - f"{ProcurementTools.formatting_instructions}" - ) + # @staticmethod + # @kernel_function(description="Conduct a survey of a supplier.") + # async def conduct_supplier_survey(supplier_name: str) -> str: + # return ( + # f"##### Supplier Survey Conducted\n" + # f"**Supplier:** {supplier_name}\n\n" + # f"Survey of supplier {supplier_name} conducted.\n" + # f"{ProcurementTools.formatting_instructions}" + # ) @staticmethod @kernel_function( @@ -636,7 +636,7 @@ def generate_tools_json_doc(cls) -> str: tools_list.append(tool_entry) # Return the JSON string representation - return json.dumps(tools_list, ensure_ascii=False, indent=2) + return json.dumps(tools_list, ensure_ascii=False) # This function does NOT have the kernel_function annotation # because it's meant for introspection rather than being exposed as a tool diff --git a/src/backend/kernel_tools/product_tools.py b/src/backend/kernel_tools/product_tools.py index 507445d57..fbe3f7989 100644 --- a/src/backend/kernel_tools/product_tools.py +++ b/src/backend/kernel_tools/product_tools.py @@ -2,7 +2,6 @@ import inspect import time -from datetime import datetime from typing import Annotated, Callable, List from semantic_kernel.functions import kernel_function @@ -75,19 +74,17 @@ async def get_product_info() -> str: """ return f"Here is information to relay back to the user. Repeat back all the relevant sections that the user asked for: {product_info}." - @staticmethod - @kernel_function( - description="Retrieve the customer's recurring billing date information." - ) - async def get_billing_date() -> str: - """Get information about the recurring billing date.""" - now = datetime.now() - start_of_month = datetime(now.year, now.month, 1) - start_of_month_string = start_of_month.strftime("%Y-%m-%d") - formatted_date = format_date_for_user(start_of_month_string) - return ( - f"## Billing Date\nYour most recent billing date was **{formatted_date}**." - ) + # @staticmethod + # @kernel_function( + # description="Retrieve the customer's recurring billing date information." + # ) + # async def get_billing_date() -> str: + # """Get information about the recurring billing date.""" + # now = datetime.now() + # start_of_month = datetime(now.year, now.month, 1) + # start_of_month_string = start_of_month.strftime("%Y-%m-%d") + # formatted_date = format_date_for_user(start_of_month_string) + # return f"## Billing Date\nYour most recent billing date was **{formatted_date}**." @staticmethod @kernel_function( @@ -122,15 +119,15 @@ async def add_new_product( return message - @staticmethod - @kernel_function( - description="Update the price of a specified product in the system." - ) - async def update_product_price(product_name: str, price: float) -> str: - """Update the price of a specific product.""" - message = f"## Price Update\nPrice for **'{product_name}'** updated to **${price:.2f}**." + # @staticmethod + # @kernel_function( + # description="Update the price of a specified product in the system." + # ) + # async def update_product_price(product_name: str, price: float) -> str: + # """Update the price of a specific product.""" + # message = f"## Price Update\nPrice for **'{product_name}'** updated to **${price:.2f}**." - return message + # return message @staticmethod @kernel_function(description="Schedule a product launch event on a specific date.") @@ -141,23 +138,23 @@ async def schedule_product_launch(product_name: str, launch_date: str) -> str: return message - @staticmethod - @kernel_function( - description="Analyze sales data for a product over a specified time period." - ) - async def analyze_sales_data(product_name: str, time_period: str) -> str: - """Analyze sales data for a product over a given time period.""" - analysis = f"## Sales Data Analysis\nSales data for **'{product_name}'** over **{time_period}** analyzed." + # @staticmethod + # @kernel_function( + # description="Analyze sales data for a product over a specified time period." + # ) + # async def analyze_sales_data(product_name: str, time_period: str) -> str: + # """Analyze sales data for a product over a given time period.""" + # analysis = f"## Sales Data Analysis\nSales data for **'{product_name}'** over **{time_period}** analyzed." - return analysis + # return analysis - @staticmethod - @kernel_function(description="Retrieve customer feedback for a specified product.") - async def get_customer_feedback(product_name: str) -> str: - """Retrieve customer feedback for a specific product.""" - feedback = f"## Customer Feedback\nCustomer feedback for **'{product_name}'** retrieved." + # @staticmethod + # @kernel_function(description="Retrieve customer feedback for a specified product.") + # async def get_customer_feedback(product_name: str) -> str: + # """Retrieve customer feedback for a specific product.""" + # feedback = f"## Customer Feedback\nCustomer feedback for **'{product_name}'** retrieved." - return feedback + # return feedback @staticmethod @kernel_function( @@ -185,17 +182,17 @@ async def coordinate_with_marketing( return message - @staticmethod - @kernel_function( - description="Review and assess the quality of a specified product." - ) - async def review_product_quality(product_name: str) -> str: - """Review the quality of a specific product.""" - review = ( - f"## Quality Review\nQuality review for **'{product_name}'** completed." - ) + # @staticmethod + # @kernel_function( + # description="Review and assess the quality of a specified product." + # ) + # async def review_product_quality(product_name: str) -> str: + # """Review the quality of a specific product.""" + # review = ( + # f"## Quality Review\nQuality review for **'{product_name}'** completed." + # ) - return review + # return review @staticmethod @kernel_function( @@ -207,17 +204,17 @@ async def handle_product_recall(product_name: str, recall_reason: str) -> str: return message - @staticmethod - @kernel_function( - description="Provide product recommendations based on customer preferences." - ) - async def provide_product_recommendations( - customer_preferences: Annotated[str, "Customer preferences or requirements"], - ) -> str: - """Provide product recommendations based on customer preferences.""" - recommendations = f"## Product Recommendations\nProduct recommendations based on preferences **'{customer_preferences}'** provided." + # @staticmethod + # @kernel_function( + # description="Provide product recommendations based on customer preferences." + # ) + # async def provide_product_recommendations( + # customer_preferences: Annotated[str, "Customer preferences or requirements"], + # ) -> str: + # """Provide product recommendations based on customer preferences.""" + # recommendations = f"## Product Recommendations\nProduct recommendations based on preferences **'{customer_preferences}'** provided." - return recommendations + # return recommendations @staticmethod @kernel_function(description="Generate a detailed report for a specified product.") @@ -227,35 +224,35 @@ async def generate_product_report(product_name: str, report_type: str) -> str: return report - @staticmethod - @kernel_function( - description="Manage supply chain activities for a specified product with a particular supplier." - ) - async def manage_supply_chain(product_name: str, supplier_name: str) -> str: - """Manage supply chain activities for a specific product.""" - message = f"## Supply Chain Management\nSupply chain for **'{product_name}'** managed with supplier **'{supplier_name}'**." + # @staticmethod + # @kernel_function( + # description="Manage supply chain activities for a specified product with a particular supplier." + # ) + # async def manage_supply_chain(product_name: str, supplier_name: str) -> str: + # """Manage supply chain activities for a specific product.""" + # message = f"## Supply Chain Management\nSupply chain for **'{product_name}'** managed with supplier **'{supplier_name}'**." - return message + # return message - @staticmethod - @kernel_function( - description="Track the shipment status of a specified product using a tracking number." - ) - async def track_product_shipment(product_name: str, tracking_number: str) -> str: - """Track the shipment of a specific product.""" - status = f"## Shipment Tracking\nShipment for **'{product_name}'** with tracking number **'{tracking_number}'** tracked." + # @staticmethod + # @kernel_function( + # description="Track the shipment status of a specified product using a tracking number." + # ) + # async def track_product_shipment(product_name: str, tracking_number: str) -> str: + # """Track the shipment of a specific product.""" + # status = f"## Shipment Tracking\nShipment for **'{product_name}'** with tracking number **'{tracking_number}'** tracked." - return status + # return status - @staticmethod - @kernel_function( - description="Set the reorder threshold level for a specified product." - ) - async def set_reorder_level(product_name: str, reorder_level: int) -> str: - """Set the reorder level for a specific product.""" - message = f"## Reorder Level Set\nReorder level for **'{product_name}'** set to **{reorder_level}** units." + # @staticmethod + # @kernel_function( + # description="Set the reorder threshold level for a specified product." + # ) + # async def set_reorder_level(product_name: str, reorder_level: int) -> str: + # """Set the reorder level for a specific product.""" + # message = f"## Reorder Level Set\nReorder level for **'{product_name}'** set to **{reorder_level}** units." - return message + # return message @staticmethod @kernel_function( @@ -290,67 +287,67 @@ async def collaborate_with_tech_team( return message - @staticmethod - @kernel_function( - description="Update the description information for a specified product." - ) - async def update_product_description(product_name: str, description: str) -> str: - """Update the description of a specific product.""" - message = f"## Product Description Updated\nDescription for **'{product_name}'** updated to:\n\n{description}" + # @staticmethod + # @kernel_function( + # description="Update the description information for a specified product." + # ) + # async def update_product_description(product_name: str, description: str) -> str: + # """Update the description of a specific product.""" + # message = f"## Product Description Updated\nDescription for **'{product_name}'** updated to:\n\n{description}" - return message + # return message - @staticmethod - @kernel_function(description="Set a percentage discount for a specified product.") - async def set_product_discount( - product_name: str, discount_percentage: float - ) -> str: - """Set a discount for a specific product.""" - message = f"## Discount Set\nDiscount for **'{product_name}'** set to **{discount_percentage}%**." + # @staticmethod + # @kernel_function(description="Set a percentage discount for a specified product.") + # async def set_product_discount( + # product_name: str, discount_percentage: float + # ) -> str: + # """Set a discount for a specific product.""" + # message = f"## Discount Set\nDiscount for **'{product_name}'** set to **{discount_percentage}%**." - return message + # return message - @staticmethod - @kernel_function( - description="Process and manage product returns with detailed reason tracking." - ) - async def manage_product_returns(product_name: str, return_reason: str) -> str: - """Manage returns for a specific product.""" - message = f"## Product Return Managed\nReturn for **'{product_name}'** managed due to:\n\n{return_reason}" + # @staticmethod + # @kernel_function( + # description="Process and manage product returns with detailed reason tracking." + # ) + # async def manage_product_returns(product_name: str, return_reason: str) -> str: + # """Manage returns for a specific product.""" + # message = f"## Product Return Managed\nReturn for **'{product_name}'** managed due to:\n\n{return_reason}" - return message + # return message - @staticmethod - @kernel_function(description="Conduct a customer survey about a specified product.") - async def conduct_product_survey(product_name: str, survey_details: str) -> str: - """Conduct a survey for a specific product.""" - message = f"## Product Survey Conducted\nSurvey for **'{product_name}'** conducted with details:\n\n{survey_details}" + # @staticmethod + # @kernel_function(description="Conduct a customer survey about a specified product.") + # async def conduct_product_survey(product_name: str, survey_details: str) -> str: + # """Conduct a survey for a specific product.""" + # message = f"## Product Survey Conducted\nSurvey for **'{product_name}'** conducted with details:\n\n{survey_details}" - return message + # return message - @staticmethod - @kernel_function( - description="Handle and process customer complaints about a specified product." - ) - async def handle_product_complaints( - product_name: str, complaint_details: str - ) -> str: - """Handle complaints for a specific product.""" - message = f"## Product Complaint Handled\nComplaint for **'{product_name}'** handled with details:\n\n{complaint_details}" + # @staticmethod + # @kernel_function( + # description="Handle and process customer complaints about a specified product." + # ) + # async def handle_product_complaints( + # product_name: str, complaint_details: str + # ) -> str: + # """Handle complaints for a specific product.""" + # message = f"## Product Complaint Handled\nComplaint for **'{product_name}'** handled with details:\n\n{complaint_details}" - return message + # return message - @staticmethod - @kernel_function( - description="Update the technical specifications for a specified product." - ) - async def update_product_specifications( - product_name: str, specifications: str - ) -> str: - """Update the specifications for a specific product.""" - message = f"## Product Specifications Updated\nSpecifications for **'{product_name}'** updated to:\n\n{specifications}" + # @staticmethod + # @kernel_function( + # description="Update the technical specifications for a specified product." + # ) + # async def update_product_specifications( + # product_name: str, specifications: str + # ) -> str: + # """Update the specifications for a specific product.""" + # message = f"## Product Specifications Updated\nSpecifications for **'{product_name}'** updated to:\n\n{specifications}" - return message + # return message @staticmethod @kernel_function( @@ -374,14 +371,14 @@ async def manage_product_listing(product_name: str, listing_details: str) -> str return message - @staticmethod - @kernel_function(description="Set the availability status of a specified product.") - async def set_product_availability(product_name: str, availability: bool) -> str: - """Set the availability status of a specific product.""" - status = "available" if availability else "unavailable" - message = f"## Product Availability Set\nProduct **'{product_name}'** is now **{status}**." + # @staticmethod + # @kernel_function(description="Set the availability status of a specified product.") + # async def set_product_availability(product_name: str, availability: bool) -> str: + # """Set the availability status of a specific product.""" + # status = "available" if availability else "unavailable" + # message = f"## Product Availability Set\nProduct **'{product_name}'** is now **{status}**." - return message + # return message @staticmethod @kernel_function( @@ -395,18 +392,18 @@ async def coordinate_with_logistics( return message - @staticmethod - @kernel_function( - description="Calculate the profit margin for a specified product using cost and selling prices." - ) - async def calculate_product_margin( - product_name: str, cost_price: float, selling_price: float - ) -> str: - """Calculate the profit margin for a specific product.""" - margin = ((selling_price - cost_price) / selling_price) * 100 - message = f"## Profit Margin Calculated\nProfit margin for **'{product_name}'** calculated at **{margin:.2f}%**." + # @staticmethod + # @kernel_function( + # description="Calculate the profit margin for a specified product using cost and selling prices." + # ) + # async def calculate_product_margin( + # product_name: str, cost_price: float, selling_price: float + # ) -> str: + # """Calculate the profit margin for a specific product.""" + # margin = ((selling_price - cost_price) / selling_price) * 100 + # message = f"## Profit Margin Calculated\nProfit margin for **'{product_name}'** calculated at **{margin:.2f}%**." - return message + # return message @staticmethod @kernel_function( @@ -418,38 +415,38 @@ async def update_product_category(product_name: str, category: str) -> str: return message - @staticmethod - @kernel_function( - description="Create and manage product bundles with multiple products." - ) - async def manage_product_bundles(bundle_name: str, product_list: List[str]) -> str: - """Manage product bundles.""" - products = ", ".join(product_list) - message = f"## Product Bundle Managed\nProduct bundle **'{bundle_name}'** managed with products:\n\n{products}" + # @staticmethod + # @kernel_function( + # description="Create and manage product bundles with multiple products." + # ) + # async def manage_product_bundles(bundle_name: str, product_list: List[str]) -> str: + # """Manage product bundles.""" + # products = ", ".join(product_list) + # message = f"## Product Bundle Managed\nProduct bundle **'{bundle_name}'** managed with products:\n\n{products}" - return message + # return message - @staticmethod - @kernel_function( - description="Optimize the product page for better user experience and performance." - ) - async def optimize_product_page( - product_name: str, optimization_details: str - ) -> str: - """Optimize the product page for better performance.""" - message = f"## Product Page Optimized\nProduct page for **'{product_name}'** optimized with details:\n\n{optimization_details}" + # @staticmethod + # @kernel_function( + # description="Optimize the product page for better user experience and performance." + # ) + # async def optimize_product_page( + # product_name: str, optimization_details: str + # ) -> str: + # """Optimize the product page for better performance.""" + # message = f"## Product Page Optimized\nProduct page for **'{product_name}'** optimized with details:\n\n{optimization_details}" - return message + # return message - @staticmethod - @kernel_function( - description="Monitor and track performance metrics for a specified product." - ) - async def monitor_product_performance(product_name: str) -> str: - """Monitor the performance of a specific product.""" - message = f"## Product Performance Monitored\nPerformance for **'{product_name}'** monitored." + # @staticmethod + # @kernel_function( + # description="Monitor and track performance metrics for a specified product." + # ) + # async def monitor_product_performance(product_name: str) -> str: + # """Monitor the performance of a specific product.""" + # message = f"## Product Performance Monitored\nPerformance for **'{product_name}'** monitored." - return message + # return message @staticmethod @kernel_function( @@ -471,47 +468,47 @@ async def create_training_material( return message - @staticmethod - @kernel_function( - description="Update the labeling information for a specified product." - ) - async def update_product_labels(product_name: str, label_details: str) -> str: - """Update labels for a specific product.""" - message = f"## Product Labels Updated\nLabels for **'{product_name}'** updated with details:\n\n{label_details}" + # @staticmethod + # @kernel_function( + # description="Update the labeling information for a specified product." + # ) + # async def update_product_labels(product_name: str, label_details: str) -> str: + # """Update labels for a specific product.""" + # message = f"## Product Labels Updated\nLabels for **'{product_name}'** updated with details:\n\n{label_details}" - return message + # return message - @staticmethod - @kernel_function( - description="Manage warranty terms and conditions for a specified product." - ) - async def manage_product_warranty(product_name: str, warranty_details: str) -> str: - """Manage the warranty for a specific product.""" - message = f"## Product Warranty Managed\nWarranty for **'{product_name}'** managed with details:\n\n{warranty_details}" + # @staticmethod + # @kernel_function( + # description="Manage warranty terms and conditions for a specified product." + # ) + # async def manage_product_warranty(product_name: str, warranty_details: str) -> str: + # """Manage the warranty for a specific product.""" + # message = f"## Product Warranty Managed\nWarranty for **'{product_name}'** managed with details:\n\n{warranty_details}" - return message + # return message - @staticmethod - @kernel_function( - description="Forecast future demand for a specified product over a time period." - ) - async def forecast_product_demand(product_name: str, forecast_period: str) -> str: - """Forecast demand for a specific product.""" - message = f"## Demand Forecast\nDemand for **'{product_name}'** forecasted for **{forecast_period}**." + # @staticmethod + # @kernel_function( + # description="Forecast future demand for a specified product over a time period." + # ) + # async def forecast_product_demand(product_name: str, forecast_period: str) -> str: + # """Forecast demand for a specific product.""" + # message = f"## Demand Forecast\nDemand for **'{product_name}'** forecasted for **{forecast_period}**." - return message + # return message - @staticmethod - @kernel_function( - description="Handle licensing agreements and requirements for a specified product." - ) - async def handle_product_licensing( - product_name: str, licensing_details: str - ) -> str: - """Handle licensing for a specific product.""" - message = f"## Product Licensing Handled\nLicensing for **'{product_name}'** handled with details:\n\n{licensing_details}" + # @staticmethod + # @kernel_function( + # description="Handle licensing agreements and requirements for a specified product." + # ) + # async def handle_product_licensing( + # product_name: str, licensing_details: str + # ) -> str: + # """Handle licensing for a specific product.""" + # message = f"## Product Licensing Handled\nLicensing for **'{product_name}'** handled with details:\n\n{licensing_details}" - return message + # return message @staticmethod @kernel_function( @@ -695,7 +692,7 @@ def generate_tools_json_doc(cls) -> str: tools_list.append(tool_entry) # Return the JSON string representation - return json.dumps(tools_list, ensure_ascii=False, indent=2) + return json.dumps(tools_list, ensure_ascii=False) # This function does NOT have the kernel_function annotation # because it's meant for introspection rather than being exposed as a tool diff --git a/src/backend/kernel_tools/tech_support_tools.py b/src/backend/kernel_tools/tech_support_tools.py index 2e6f8f077..99660750b 100644 --- a/src/backend/kernel_tools/tech_support_tools.py +++ b/src/backend/kernel_tools/tech_support_tools.py @@ -378,7 +378,7 @@ def generate_tools_json_doc(cls) -> str: tools_list.append(tool_entry) # Return the JSON string representation - return json.dumps(tools_list, ensure_ascii=False, indent=2) + return json.dumps(tools_list, ensure_ascii=False) # This function does NOT have the kernel_function annotation # because it's meant for introspection rather than being exposed as a tool diff --git a/src/backend/pyproject.toml b/src/backend/pyproject.toml index 9d0379dea..180ce758a 100644 --- a/src/backend/pyproject.toml +++ b/src/backend/pyproject.toml @@ -7,8 +7,8 @@ requires-python = ">=3.11" dependencies = [ "azure-ai-evaluation>=1.5.0", "azure-ai-inference>=1.0.0b9", - "azure-ai-projects>=1.0.0b9", - "azure-ai-agents>=1.2.0b1", + "azure-ai-projects==1.0.0", + "azure-ai-agents==1.2.0b2", "azure-cosmos>=4.9.0", "azure-identity>=1.21.0", "azure-monitor-events-extension>=0.1.0", @@ -27,7 +27,7 @@ dependencies = [ "pytest-cov==5.0.0", "python-dotenv>=1.1.0", "python-multipart>=0.0.20", - "semantic-kernel[azure]>=1.32.2", + "semantic-kernel==1.35.3", "uvicorn>=0.34.2", "pylint-pydantic>=0.3.5", "pexpect>=4.9.0", diff --git a/src/backend/tests/models/test_messages.py b/src/backend/tests/models/test_messages.py index 98a5e931a..fb7d158e9 100644 --- a/src/backend/tests/models/test_messages.py +++ b/src/backend/tests/models/test_messages.py @@ -3,7 +3,7 @@ import uuid from models.messages import ( DataType, - BAgentType, + AgentType as BAgentType, # map to your enum StepStatus, PlanStatus, HumanFeedbackStatus, @@ -20,7 +20,7 @@ def test_enum_values(): """Test enumeration values for consistency.""" assert DataType.session == "session" assert DataType.plan == "plan" - assert BAgentType.human_agent == "HumanAgent" + assert BAgentType.HUMAN == "Human_Agent" # was human_agent / "HumanAgent" assert StepStatus.completed == "completed" assert PlanStatus.in_progress == "in_progress" assert HumanFeedbackStatus.requested == "requested" @@ -31,7 +31,7 @@ def test_plan_with_steps_update_counts(): step1 = Step( plan_id=str(uuid.uuid4()), action="Review document", - agent=BAgentType.human_agent, + agent=BAgentType.HUMAN, status=StepStatus.completed, session_id=str(uuid.uuid4()), user_id=str(uuid.uuid4()), @@ -39,7 +39,7 @@ def test_plan_with_steps_update_counts(): step2 = Step( plan_id=str(uuid.uuid4()), action="Approve document", - agent=BAgentType.hr_agent, + agent=BAgentType.HR, status=StepStatus.failed, session_id=str(uuid.uuid4()), user_id=str(uuid.uuid4()), @@ -78,10 +78,10 @@ def test_action_request_creation(): plan_id=str(uuid.uuid4()), session_id=str(uuid.uuid4()), action="Review and approve", - agent=BAgentType.procurement_agent, + agent=BAgentType.PROCUREMENT, ) assert action_request.action == "Review and approve" - assert action_request.agent == BAgentType.procurement_agent + assert action_request.agent == BAgentType.PROCUREMENT def test_human_feedback_creation(): @@ -114,7 +114,7 @@ def test_step_defaults(): step = Step( plan_id=str(uuid.uuid4()), action="Prepare report", - agent=BAgentType.generic_agent, + agent=BAgentType.GENERIC, session_id=str(uuid.uuid4()), user_id=str(uuid.uuid4()), ) diff --git a/src/backend/tests/test_app.py b/src/backend/tests/test_app.py index 5fa83548d..0bb6f674f 100644 --- a/src/backend/tests/test_app.py +++ b/src/backend/tests/test_app.py @@ -24,13 +24,51 @@ os.environ["AZURE_OPENAI_API_VERSION"] = "2023-01-01" os.environ["AZURE_OPENAI_ENDPOINT"] = "https://mock-openai-endpoint" +# Ensure repo root is on sys.path so `src.backend...` imports work +ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..")) +if ROOT_DIR not in sys.path: + sys.path.insert(0, ROOT_DIR) + +# Provide safe defaults for vars that app_config reads at import-time +os.environ.setdefault("AZURE_AI_SUBSCRIPTION_ID", "00000000-0000-0000-0000-000000000000") +os.environ.setdefault("AZURE_AI_RESOURCE_GROUP", "rg-test") +os.environ.setdefault("AZURE_AI_PROJECT_NAME", "proj-test") +os.environ.setdefault("AZURE_AI_AGENT_ENDPOINT", "https://agents.example.com/") +os.environ.setdefault("USER_LOCAL_BROWSER_LANGUAGE", "en-US") + # Mock telemetry initialization to prevent errors with patch("azure.monitor.opentelemetry.configure_azure_monitor", MagicMock()): - from app_kernel import app + try: + from src.backend.app import app # preferred if file exists + except ModuleNotFoundError: + # fallback to app_kernel which exists in this repo + import importlib + mod = importlib.import_module("src.backend.app_kernel") + app = getattr(mod, "app", None) + if app is None: + create_app = getattr(mod, "create_app", None) + if create_app is not None: + app = create_app() + else: + raise # Initialize FastAPI test client client = TestClient(app) +from fastapi.routing import APIRoute + +def _find_input_task_path(app): + for r in app.routes: + if isinstance(r, APIRoute): + # prefer exact or known names, but fall back to substring + if r.name in ("input_task", "handle_input_task"): + return r.path + if "input_task" in r.path: + return r.path + return "/input_task" # fallback + +INPUT_TASK_PATH = _find_input_task_path(app) + @pytest.fixture(autouse=True) def mock_dependencies(monkeypatch): @@ -39,12 +77,15 @@ def mock_dependencies(monkeypatch): "auth.auth_utils.get_authenticated_user_details", lambda headers: {"user_principal_id": "mock-user-id"}, ) + monkeypatch.setattr( + "src.backend.utils_kernel.retrieve_all_agent_tools", + lambda: [{"agent": "test_agent", "function": "test_function"}], + raising=False, # allow creating the attr if it doesn't exist + ) def test_input_task_invalid_json(): """Test the case where the input JSON is invalid.""" - invalid_json = "Invalid JSON data" - headers = {"Authorization": "Bearer mock-token"} response = client.post("/input_task", data=invalid_json, headers=headers) @@ -165,15 +206,9 @@ def test_process_request_endpoint_real_rai_check(): def test_input_task_missing_description(): """Test the case where the input task description is missing.""" - input_task = { - "session_id": None, - "user_id": "mock-user-id", - } - + input_task = {"session_id": None, "user_id": "mock-user-id"} headers = {"Authorization": "Bearer mock-token"} - response = client.post("/input_task", json=input_task, headers=headers) - - # Assert response for missing description + response = client.post(INPUT_TASK_PATH, json=input_task, headers=headers) assert response.status_code == 422 assert "detail" in response.json() @@ -188,10 +223,9 @@ def test_input_task_empty_description(): """Tests if /input_task handles an empty description.""" empty_task = {"session_id": None, "user_id": "mock-user-id", "description": ""} headers = {"Authorization": "Bearer mock-token"} - response = client.post("/input_task", json=empty_task, headers=headers) - + response = client.post(INPUT_TASK_PATH, json=empty_task, headers=headers) assert response.status_code == 422 - assert "detail" in response.json() # Assert error message for missing description + assert "detail" in response.json() if __name__ == "__main__": diff --git a/src/backend/tests/test_config.py b/src/backend/tests/test_config.py index 8c4ebe13a..5b9cae1f9 100644 --- a/src/backend/tests/test_config.py +++ b/src/backend/tests/test_config.py @@ -1,49 +1,70 @@ -# tests/test_config.py -from unittest.mock import patch +# src/backend/tests/test_config.py import os +import sys +from unittest.mock import patch -# Mock environment variables globally +# Make repo root importable so `src.backend...` works +ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..")) +if ROOT_DIR not in sys.path: + sys.path.insert(0, ROOT_DIR) + +# Mock environment variables so app_config can construct safely at import time MOCK_ENV_VARS = { + # Cosmos "COSMOSDB_ENDPOINT": "https://mock-cosmosdb.documents.azure.com:443/", "COSMOSDB_DATABASE": "mock_database", "COSMOSDB_CONTAINER": "mock_container", + + # Azure OpenAI "AZURE_OPENAI_DEPLOYMENT_NAME": "mock-deployment", - "AZURE_OPENAI_API_VERSION": "2024-05-01-preview", + "AZURE_OPENAI_API_VERSION": "2024-11-20", "AZURE_OPENAI_ENDPOINT": "https://mock-openai-endpoint.azure.com/", - "AZURE_OPENAI_API_KEY": "mock-api-key", + + # Optional auth (kept for completeness) "AZURE_TENANT_ID": "mock-tenant-id", "AZURE_CLIENT_ID": "mock-client-id", "AZURE_CLIENT_SECRET": "mock-client-secret", + + # Azure AI Project (required by current AppConfig) + "AZURE_AI_SUBSCRIPTION_ID": "00000000-0000-0000-0000-000000000000", + "AZURE_AI_RESOURCE_GROUP": "rg-test", + "AZURE_AI_PROJECT_NAME": "proj-test", + "AZURE_AI_AGENT_ENDPOINT": "https://agents.example.com/", + + # Misc + "USER_LOCAL_BROWSER_LANGUAGE": "en-US", } -with patch.dict(os.environ, MOCK_ENV_VARS): - from config import ( - Config, - GetRequiredConfig, - GetOptionalConfig, - GetBoolConfig, - ) +# Import the current config objects/functions under the mocked env +with patch.dict(os.environ, MOCK_ENV_VARS, clear=False): + # New codebase: config lives in app_config/config_kernel + from src.backend.app_config import config as app_config + from src.backend.config_kernel import Config +# Provide thin wrappers so the old test names still work +def GetRequiredConfig(name: str, default=None): + return app_config._get_required(name, default) -@patch.dict(os.environ, MOCK_ENV_VARS) +def GetOptionalConfig(name: str, default: str = ""): + return app_config._get_optional(name, default) + +def GetBoolConfig(name: str) -> bool: + return app_config._get_bool(name) + + +# ---- Tests (unchanged semantics) ---- + +@patch.dict(os.environ, MOCK_ENV_VARS, clear=False) def test_get_required_config(): - """Test GetRequiredConfig.""" assert GetRequiredConfig("COSMOSDB_ENDPOINT") == MOCK_ENV_VARS["COSMOSDB_ENDPOINT"] - -@patch.dict(os.environ, MOCK_ENV_VARS) +@patch.dict(os.environ, MOCK_ENV_VARS, clear=False) def test_get_optional_config(): - """Test GetOptionalConfig.""" assert GetOptionalConfig("NON_EXISTENT_VAR", "default_value") == "default_value" - assert ( - GetOptionalConfig("COSMOSDB_DATABASE", "default_db") - == MOCK_ENV_VARS["COSMOSDB_DATABASE"] - ) - + assert GetOptionalConfig("COSMOSDB_DATABASE", "default_db") == MOCK_ENV_VARS["COSMOSDB_DATABASE"] -@patch.dict(os.environ, MOCK_ENV_VARS) +@patch.dict(os.environ, MOCK_ENV_VARS, clear=False) def test_get_bool_config(): - """Test GetBoolConfig.""" with patch.dict("os.environ", {"FEATURE_ENABLED": "true"}): assert GetBoolConfig("FEATURE_ENABLED") is True with patch.dict("os.environ", {"FEATURE_ENABLED": "false"}): diff --git a/src/backend/uv.lock b/src/backend/uv.lock index 7f47f3b75..8dd48c4ae 100644 --- a/src/backend/uv.lock +++ b/src/backend/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.13'", @@ -7,9 +7,6 @@ resolution-markers = [ "python_full_version < '3.12'", ] -[options] -prerelease-mode = "allow" - [[package]] name = "aiohappyeyeballs" version = "2.6.1" @@ -219,21 +216,21 @@ wheels = [ [[package]] name = "azure-ai-agents" -version = "1.2.0b3" +version = "1.2.0b2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, { name = "isodate" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/52/3c1af9ed86582f09343f135d527ca26f0bf9659c01ccbddb650bbb952963/azure_ai_agents-1.2.0b3.tar.gz", hash = "sha256:440d7fca98c0b13654a57dcd159cdf64d1024f9baacd1a4354ce91a290d3741e", size = 362563, upload-time = "2025-08-22T22:41:58.609Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/07/97eb5d1355abbd572c187789ae6c17d36dfcb3a9a1fae002e660d2663bf6/azure_ai_agents-1.2.0b2.tar.gz", hash = "sha256:4d9d220c12e2b7741f67bd7ef35e4faa60de7da32c0ab2526fa0ce1b978c2537", size = 353885, upload-time = "2025-08-12T21:35:46.264Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/a4/c916745e150b5e157688da9a7965d62efb82ad940f2991260d1d2b79fcf1/azure_ai_agents-1.2.0b3-py3-none-any.whl", hash = "sha256:fec3e92fac5de2c18dee2d4def734825c2a4880bee39b3c237a7ad8079bfa8a7", size = 208129, upload-time = "2025-08-22T22:42:00.249Z" }, + { url = "https://files.pythonhosted.org/packages/73/9d/59688d265026e84dfff39b26d24cdbce0b2a2466a5bed06e0874a2a58e90/azure_ai_agents-1.2.0b2-py3-none-any.whl", hash = "sha256:f82117029fcc1dbed24d6b6c94d7e60e6b75276c333329fcfd9238853c82020b", size = 204422, upload-time = "2025-08-12T21:35:48.057Z" }, ] [[package]] name = "azure-ai-evaluation" -version = "1.10.0" +version = "1.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -249,9 +246,9 @@ dependencies = [ { name = "pyjwt" }, { name = "ruamel-yaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/6e/018e0bc3d7368fc6379373939d3ef29da75755e998545e67c660ad8efadd/azure_ai_evaluation-1.10.0.tar.gz", hash = "sha256:58bdf2d2be9e2b94a881026b006104f64654bbe61dc101bff84c2d9fa8c575a2", size = 1058944, upload-time = "2025-07-31T23:46:31.021Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/b7/586f18237fbb7e13d1dd53fb27fb668ade0f5a7e133636c61fc9a2d81939/azure_ai_evaluation-1.11.0.tar.gz", hash = "sha256:4cfaefd151deef1ef4c9021eaee9352d8817e5d2c9a654de2ff83106f21b47f8", size = 1087165, upload-time = "2025-09-03T21:02:43.812Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/38/a0ed945934833c0b3a679611351be0f1e7c8667af92a58a43da2ece512e5/azure_ai_evaluation-1.10.0-py3-none-any.whl", hash = "sha256:05bf98b29d8d0218180725d0db41f5a4d8fd394eceaacb87c79f9bca503206a9", size = 1000093, upload-time = "2025-07-31T23:46:32.97Z" }, + { url = "https://files.pythonhosted.org/packages/13/fd/477ed56cf10514b539c2de594f6179b7ecd1790728f85f23d26221d93c43/azure_ai_evaluation-1.11.0-py3-none-any.whl", hash = "sha256:b357964dbb0f22de0d9281a75e21493b1ad807469572bc9630d47c6f91196f26", size = 1017876, upload-time = "2025-09-03T21:02:45.359Z" }, ] [[package]] @@ -270,7 +267,7 @@ wheels = [ [[package]] name = "azure-ai-projects" -version = "1.1.0b2" +version = "1.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-ai-agents" }, @@ -279,9 +276,9 @@ dependencies = [ { name = "isodate" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/26/17/33664227381ff59690e16a8d3261c9edeb80d88acdb24b717733d63529bb/azure_ai_projects-1.1.0b2.tar.gz", hash = "sha256:79432e2de8b27f01aaad6d3f12e1549396f1c2a022665a859c45b179bf6ff228", size = 144848, upload-time = "2025-08-05T22:18:45.351Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/95/9c04cb5f658c7f856026aa18432e0f0fa254ead2983a3574a0f5558a7234/azure_ai_projects-1.0.0.tar.gz", hash = "sha256:b5f03024ccf0fd543fbe0f5abcc74e45b15eccc1c71ab87fc71c63061d9fd63c", size = 130798, upload-time = "2025-07-31T02:09:27.912Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/2b/98f928ea41c03c78c02e1a72fc5e9c900d2e6e472cb51f9272cb0d4ba3bf/azure_ai_projects-1.1.0b2-py3-none-any.whl", hash = "sha256:3a4ecc6de6ab27a75b4c8228cd8162c9853fd1432e77746792b0ee2088c775db", size = 125301, upload-time = "2025-08-05T22:18:46.577Z" }, + { url = "https://files.pythonhosted.org/packages/b5/db/7149cdf71e12d9737f186656176efc94943ead4f205671768c1549593efe/azure_ai_projects-1.0.0-py3-none-any.whl", hash = "sha256:81369ed7a2f84a65864f57d3fa153e16c30f411a1504d334e184fb070165a3fa", size = 115188, upload-time = "2025-07-31T02:09:29.362Z" }, ] [[package]] @@ -322,15 +319,15 @@ wheels = [ [[package]] name = "azure-cosmos" -version = "4.14.0b2" +version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2f/00/78d1e19ba7eb68edf0593769fc73f3a5673bbc90fb6be55e7b81af081d1d/azure_cosmos-4.14.0b2.tar.gz", hash = "sha256:d31983a1bbf1234a2b7b872e6d5027a056afb88f05d5db5fb2b8f382fc22124a", size = 1960622, upload-time = "2025-08-12T18:49:25.416Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/7c/a4e7810f85e7f83d94265ef5ff0fb1efad55a768de737d940151ea2eec45/azure_cosmos-4.9.0.tar.gz", hash = "sha256:c70db4cbf55b0ff261ed7bb8aa325a5dfa565d3c6eaa43d75d26ae5e2ad6d74f", size = 1824155, upload-time = "2024-11-19T04:09:30.195Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/6f/2fdfcd428f12adda9ff63b5eec0a12bf7a9c31ae4fea9f9e441b3d2c4c7a/azure_cosmos-4.14.0b2-py3-none-any.whl", hash = "sha256:2db2bd7f1f4a3408755a21859b746691e4bb6eae19d21505a5d436cdda81f6de", size = 353279, upload-time = "2025-08-12T18:49:27.372Z" }, + { url = "https://files.pythonhosted.org/packages/61/dc/380f843744535497acd0b85aacb59565c84fc28bf938c8d6e897a858cd95/azure_cosmos-4.9.0-py3-none-any.whl", hash = "sha256:3b60eaa01a16a857d0faf0cec304bac6fa8620a81bc268ce760339032ef617fe", size = 303157, upload-time = "2024-11-19T04:09:32.148Z" }, ] [[package]] @@ -405,7 +402,7 @@ wheels = [ [[package]] name = "azure-search-documents" -version = "11.6.0b12" +version = "11.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-common" }, @@ -413,14 +410,14 @@ dependencies = [ { name = "isodate" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e6/47/e9ac59089057fea910a345e3e004d4eff636af020a59b2581393702d3686/azure_search_documents-11.6.0b12.tar.gz", hash = "sha256:5366acaf4c38989324afa23cf508b12c36f0f11e40383698ee78e6fdb11bdbeb", size = 386534, upload-time = "2025-05-14T20:52:31.399Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/11/9ecde2bd9e6c00cc0e3f312ab096a33d333f8ba40c847f01f94d524895fe/azure_search_documents-11.5.3.tar.gz", hash = "sha256:6931149ec0db90485d78648407f18ea4271420473c7cb646bf87790374439989", size = 300353, upload-time = "2025-06-25T16:48:58.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/97/e806cd82ab61f624d25fb8ce6a6f0b9830005ac556e4ae9e62f15c4a8803/azure_search_documents-11.6.0b12-py3-none-any.whl", hash = "sha256:5c2b07b6e7d182a10a765f6515ae8fc86731ae6ea3f99f1e64433b5cd21bd335", size = 401657, upload-time = "2025-05-14T20:52:33.133Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f5/0f6b52567cbb33f1efba13060514ed7088a86de84d74b77cda17d278bcd9/azure_search_documents-11.5.3-py3-none-any.whl", hash = "sha256:110617751c6c8bd50b1f0af2b00a478bd4fbaf4e2f0387e3454c26ec3eb433d6", size = 298772, upload-time = "2025-06-25T16:49:00.764Z" }, ] [[package]] name = "azure-storage-blob" -version = "12.27.0b1" +version = "12.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -428,9 +425,9 @@ dependencies = [ { name = "isodate" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1f/f3/5e6f3c74ce7e18bddadace702c448425230f385d97c0655bb9966a06dd2a/azure_storage_blob-12.27.0b1.tar.gz", hash = "sha256:fb14288580dc0b83aa85bb9d25b7ee63f4d4f2746918fde76567e157d7c557ea", size = 583196, upload-time = "2025-06-12T15:08:16.311Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/95/3e3414491ce45025a1cde107b6ae72bf72049e6021597c201cd6a3029b9a/azure_storage_blob-12.26.0.tar.gz", hash = "sha256:5dd7d7824224f7de00bfeb032753601c982655173061e242f13be6e26d78d71f", size = 583332, upload-time = "2025-07-16T21:34:07.644Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/ef/f4313b22abad3b3e4f18b55a13ae4c04e6b52e88fb41ad2e5d5241c7da25/azure_storage_blob-12.27.0b1-py3-none-any.whl", hash = "sha256:7fa15a2c97d328ce246c64e84c97e4a6ade3a9c4f350640186bb3ba94ced3473", size = 412472, upload-time = "2025-06-12T15:08:19.846Z" }, + { url = "https://files.pythonhosted.org/packages/5b/64/63dbfdd83b31200ac58820a7951ddfdeed1fbee9285b0f3eae12d1357155/azure_storage_blob-12.26.0-py3-none-any.whl", hash = "sha256:8c5631b8b22b4f53ec5fff2f3bededf34cfef111e2af613ad42c9e6de00a77fe", size = 412907, upload-time = "2025-07-16T21:34:09.367Z" }, ] [[package]] @@ -463,16 +460,16 @@ dependencies = [ { name = "pytest-cov" }, { name = "python-dotenv" }, { name = "python-multipart" }, - { name = "semantic-kernel", extra = ["azure"] }, + { name = "semantic-kernel" }, { name = "uvicorn" }, ] [package.metadata] requires-dist = [ - { name = "azure-ai-agents", specifier = ">=1.2.0b1" }, + { name = "azure-ai-agents", specifier = "==1.2.0b2" }, { name = "azure-ai-evaluation", specifier = ">=1.5.0" }, { name = "azure-ai-inference", specifier = ">=1.0.0b9" }, - { name = "azure-ai-projects", specifier = ">=1.0.0b9" }, + { name = "azure-ai-projects", specifier = "==1.0.0" }, { name = "azure-cosmos", specifier = ">=4.9.0" }, { name = "azure-identity", specifier = ">=1.21.0" }, { name = "azure-monitor-events-extension", specifier = ">=0.1.0" }, @@ -494,7 +491,7 @@ requires-dist = [ { name = "pytest-cov", specifier = "==5.0.0" }, { name = "python-dotenv", specifier = ">=1.1.0" }, { name = "python-multipart", specifier = ">=0.0.20" }, - { name = "semantic-kernel", extras = ["azure"], specifier = ">=1.32.2" }, + { name = "semantic-kernel", specifier = "==1.35.3" }, { name = "uvicorn", specifier = ">=0.34.2" }, ] @@ -509,72 +506,47 @@ wheels = [ [[package]] name = "cffi" -version = "2.0.0b1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/75/84/7930c3586ca7c66a63b2d7a30d9df649ce8c3660f8da241b0661bba4e566/cffi-2.0.0b1.tar.gz", hash = "sha256:4440de58d19c0bebe6a2f3b721253d67b27aabb34e00ab35756d8699876191ea", size = 521625, upload-time = "2025-07-29T01:11:50.959Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/90/14deaf13603dfff56bb872a4d53e1043486178ae7a2ce8cc17ea5677d97e/cffi-2.0.0b1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:5f373f9bdc3569acd8aaebb6b521080eeb5a298533a58715537caf74e9e27f6b", size = 184383, upload-time = "2025-07-29T01:10:17.675Z" }, - { url = "https://files.pythonhosted.org/packages/f7/36/0a125a1ab354a95aae2165ce4c2b8fcd057706a85380670e3991052dcfcd/cffi-2.0.0b1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a898f76bac81f9a371df6c8664228a85cdea6b283a721f2493f0df6f80afd208", size = 180599, upload-time = "2025-07-29T01:10:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cb/27237bcd6c4e883104db737929f02838a7405caed422aeeb76ee5ffa14d9/cffi-2.0.0b1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:314afab228f7b45de7bae55059b4e706296e7d3984d53e643cc0389757216221", size = 203212, upload-time = "2025-07-29T01:10:20.057Z" }, - { url = "https://files.pythonhosted.org/packages/12/94/bbeddca63090c5335ad597310bd6f2011f1c8733bc71e88f53c38ac4ff4c/cffi-2.0.0b1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6de033c73dc89f80139c5a7d135fbd6c1d7b28ebb0d2df98cd1f4ef76991b15c", size = 202714, upload-time = "2025-07-29T01:10:21.401Z" }, - { url = "https://files.pythonhosted.org/packages/f4/9b/b7587a1f3f7f52795a7d125d6c6b844f7a8355cbb54ae8fdef2a03488914/cffi-2.0.0b1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffbbeedd6bac26c0373b71831d3c73181a1c100dc6fc7aadbfcca54cace417db", size = 217093, upload-time = "2025-07-29T01:10:22.481Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b2/af4e0ed2c2aded25ed54107f96d424407839bdfa7e90858f8e0f6fed6ee9/cffi-2.0.0b1-cp311-cp311-manylinux_2_27_i686.manylinux_2_28_i686.whl", hash = "sha256:c5713cac21b2351a53958c765d8e9eda45184bb757c3ccab139608e708788796", size = 209019, upload-time = "2025-07-29T01:10:23.584Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6e/899c5473c3d7cc89815db894abcd81cd976a1f314c142e708aef3c0982a3/cffi-2.0.0b1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:71ab35c6cc375da1e2c06af65bf0b5049199ad9b264f9ed7c90c0fe9450900e3", size = 215662, upload-time = "2025-07-29T01:10:24.997Z" }, - { url = "https://files.pythonhosted.org/packages/1c/8e/953a07806f307bf1089239858013cc81c6d5cc8ca23593704b0530429302/cffi-2.0.0b1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:53c780c2ec8ce0e5db9b74e9b0b55ff5d5f70071202740cef073a2771fa1d2ce", size = 219015, upload-time = "2025-07-29T01:10:27.077Z" }, - { url = "https://files.pythonhosted.org/packages/ea/0a/ffd99099d96a911236decff459cb330a1c046483008456b23554f62c81c6/cffi-2.0.0b1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:be957dd266facf8e4925643073159b05021a990b46620b06ca27eaf9d900dbc2", size = 212021, upload-time = "2025-07-29T01:10:28.527Z" }, - { url = "https://files.pythonhosted.org/packages/2f/00/c68c1a1665a28dfb8c848668f128d0f1919dc8e843f2e20ce90bce7b60d8/cffi-2.0.0b1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:16dc303af3630f54186b86aadf1121badf3cba6de17dfeacb84c5091e059a690", size = 217124, upload-time = "2025-07-29T01:10:29.877Z" }, - { url = "https://files.pythonhosted.org/packages/de/a7/194d80668bebc5a6a8d95ec5f3a1f186e8d87c864882c96a9ec2ecbd06a8/cffi-2.0.0b1-cp311-cp311-win32.whl", hash = "sha256:504d264944d0934d7b02164af5c62b175255ef0d39c5142d95968b710c58a8f6", size = 172111, upload-time = "2025-07-29T01:10:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b6/0002211aab83b6bfbdba09dc8cd354e44c49216e6207999b9f0d1d0053cb/cffi-2.0.0b1-cp311-cp311-win_amd64.whl", hash = "sha256:e2920fa42cf0616c21ea6d3948ad207cf0e420d2d2ef449d86ccad6ef9c13393", size = 182858, upload-time = "2025-07-29T01:10:32.021Z" }, - { url = "https://files.pythonhosted.org/packages/52/9e/c6773b5b91b20c5642166c57503a9c67c6948ae4009aa4d2ce233a6b570f/cffi-2.0.0b1-cp311-cp311-win_arm64.whl", hash = "sha256:142c9c0c75fbc95ce23836e538681bd89e483de37b7cdf251dbdf0975995f8ac", size = 177421, upload-time = "2025-07-29T01:10:33.191Z" }, - { url = "https://files.pythonhosted.org/packages/50/20/432dc366952574ea190bce0a2970f92e676e972c78ef501d58406b459883/cffi-2.0.0b1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9d04b5fc06ba0ce45d7e51dfd8a14dc20708ef301fcf5a215c507f4e084b00c8", size = 185303, upload-time = "2025-07-29T01:10:34.291Z" }, - { url = "https://files.pythonhosted.org/packages/54/2d/e89016a2019212d54be2523756faa5b2c3ab8cb6f520a82e0d6bcacd527d/cffi-2.0.0b1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b17e92900eb61bce62ea07ea8dd0dc33aa476ee8f977918050e52f90f5b645c", size = 181101, upload-time = "2025-07-29T01:10:35.641Z" }, - { url = "https://files.pythonhosted.org/packages/89/4f/6978a38ee0d8976f3087c09e779f9306ed51b9fb68ce5e3606244f6e2469/cffi-2.0.0b1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2155d2a0819c3fdcaa37832fb69e698d455627c23f83bc9c7adbef699fe4be19", size = 208122, upload-time = "2025-07-29T01:10:36.757Z" }, - { url = "https://files.pythonhosted.org/packages/20/2f/568d19b010aa304f6f55aaf160834e0db9677943b0c268462876c4e1c0ef/cffi-2.0.0b1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4210ddc2b41c20739c64dede1304fb81415220ea671885623063fab44066e376", size = 206747, upload-time = "2025-07-29T01:10:37.837Z" }, - { url = "https://files.pythonhosted.org/packages/bf/7b/171907beef5622bc6164ae9db94eaaa8e56bfb986f375742a9669ecc18f7/cffi-2.0.0b1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:31b8e3204cdef043e59a296383e6a43461d17c5c3d73fa9cebf4716a561291b0", size = 220804, upload-time = "2025-07-29T01:10:39.299Z" }, - { url = "https://files.pythonhosted.org/packages/49/2a/539d6021b1570308159745e775d0bd4164e43957e515bffd33cb6e57cf06/cffi-2.0.0b1-cp312-cp312-manylinux_2_27_i686.manylinux_2_28_i686.whl", hash = "sha256:cbde39be02aa7d8fbcd6bf1a9241cb1d84f2e2f0614970c51a707a9a176b85c6", size = 211912, upload-time = "2025-07-29T01:10:40.767Z" }, - { url = "https://files.pythonhosted.org/packages/87/a9/2cddc8eeabd7b32d494de5bb9db95e3816b47ad00e05269b33e2bb8be9f3/cffi-2.0.0b1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ea57043b545f346b081877737cb0320960012107d0250fa5183a4306f9365d6", size = 219528, upload-time = "2025-07-29T01:10:42.419Z" }, - { url = "https://files.pythonhosted.org/packages/a8/18/49ff9cbe89eae3fff54a7af79474dd897bac44325073a6a7dc9b7ae4b64e/cffi-2.0.0b1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d31ba9f54739dcf98edb87e4881e326fad79e4866137c24afb0da531c1a965ca", size = 223011, upload-time = "2025-07-29T01:10:43.906Z" }, - { url = "https://files.pythonhosted.org/packages/a1/1e/4f10dd0fd9cb8d921620663beb497af0a6175c96cecd87e5baf613d0c947/cffi-2.0.0b1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27309de8cebf48e056550db6607e2fb2c50109b54fc72c02b3b34811233483be", size = 221408, upload-time = "2025-07-29T01:10:45.385Z" }, - { url = "https://files.pythonhosted.org/packages/00/82/cbbb23951d9890475f151c1137d067a712e7f1e59509def619c5d9a645aa/cffi-2.0.0b1-cp312-cp312-win32.whl", hash = "sha256:f4b5acb4cddcaf0ebb82a226f9fa1d5063505e0c206031ee1f4d173750b592fd", size = 172972, upload-time = "2025-07-29T01:10:46.458Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6b/e52b88ee438acd26fd84963f357a90ce8f4494cc7d94cbde1b26e199bd22/cffi-2.0.0b1-cp312-cp312-win_amd64.whl", hash = "sha256:cf1b2510f1a91c4d7e8f83df6a13404332421e6e4a067059174d455653ae5314", size = 183592, upload-time = "2025-07-29T01:10:47.916Z" }, - { url = "https://files.pythonhosted.org/packages/73/ac/3a5a182637b9a02c16335743b14485cb916ca984dcdc18737851732bff16/cffi-2.0.0b1-cp312-cp312-win_arm64.whl", hash = "sha256:bd7ce5d8224fb5a57bd7f1d9843aa4ecb870ec3f4a2101e1ba8314e91177e184", size = 177583, upload-time = "2025-07-29T01:10:49.091Z" }, - { url = "https://files.pythonhosted.org/packages/8e/5b/d5307bdfac914ec977af904947ead0f22013e066aff82a215a5ff7db5e20/cffi-2.0.0b1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a160995771c54b12dc5a1ef44d6fd59aeea4909e2d58c10169156e9d9a7e2960", size = 185280, upload-time = "2025-07-29T01:10:50.173Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f5/b1fc8c8508e724b824713cd829cb5f0a39e182619ffc4d4bc1a8f142040d/cffi-2.0.0b1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9c70c77ec47b96a593477386d7bf23243996c75f1cc7ce383ba35dcedca9bd14", size = 181098, upload-time = "2025-07-29T01:10:51.592Z" }, - { url = "https://files.pythonhosted.org/packages/1a/2e/2fdbdfb2783a103176c78fc9833aff80080b6567e90647e05e35160d4082/cffi-2.0.0b1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:47a91ab8d17ed7caed27e5b2eda3b3478f3d28cecb3939d708545804273e159b", size = 208101, upload-time = "2025-07-29T01:10:53.059Z" }, - { url = "https://files.pythonhosted.org/packages/1f/23/4eea412e3aa8173bad1ad77fc28905aa393bf4738221fc4dc99587157940/cffi-2.0.0b1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fd8f55419576289d7cd8c9349ea46a222379936136754ab4c2b041294b0b48d", size = 206671, upload-time = "2025-07-29T01:10:54.652Z" }, - { url = "https://files.pythonhosted.org/packages/c4/c1/3c334b249ae3faa1b5126c9db797561be3669d29f8096675b5d0e55754e3/cffi-2.0.0b1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:916141ca9ff05e9f67fe73c39a527d96a7101191673dee9985e71cd164b55915", size = 220797, upload-time = "2025-07-29T01:10:55.826Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4a/67cf1060b419ea26ffb79dd645371246cffd3c7cf5fca5c7cd66769e7323/cffi-2.0.0b1-cp313-cp313-manylinux_2_27_i686.manylinux_2_28_i686.whl", hash = "sha256:91fc109a1412dd29657f442a61bb571baaa1d074628145008ceb54dc9bb13941", size = 211900, upload-time = "2025-07-29T01:10:57.298Z" }, - { url = "https://files.pythonhosted.org/packages/de/df/d890a3638e86f9abe533d95bf08b5d5ec140c3a0befad9a3e9edc8546553/cffi-2.0.0b1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b08dd1a826b678d39aa78f30edc1b7d9bd1e5b7e5adc2d47e8f56ab25ac7c13", size = 219467, upload-time = "2025-07-29T01:10:58.819Z" }, - { url = "https://files.pythonhosted.org/packages/e8/2b/079e4e0535b72066029bd58438a3f6c538623742d31f80467d340cbaf8d9/cffi-2.0.0b1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76a19efb88a495bb7377fc542c7f97c9816dfc1d6bb4ad147acb99599a83e248", size = 222974, upload-time = "2025-07-29T01:11:00.179Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e3/3428e9dbf24464bc04af09ad298b28c48a9481f0a89924f619388354734b/cffi-2.0.0b1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:87acb9e2221ed37c385c9cef866377fbaa13180de9ba1cdc4e6dc927b273c87f", size = 221343, upload-time = "2025-07-29T01:11:01.718Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d8/9eba61d92eaf59ce97d85855895ed1961330c2e9a0ba9f922c920808b303/cffi-2.0.0b1-cp313-cp313-win32.whl", hash = "sha256:60c2c1d7adf558b932de9e4633f68e359063d1a748c92a4a3cba832085e9819b", size = 172947, upload-time = "2025-07-29T01:11:02.835Z" }, - { url = "https://files.pythonhosted.org/packages/fb/84/582fc182fe8994b495a0dde875c30ec9202154f13dfc1bbea96233b6ae1b/cffi-2.0.0b1-cp313-cp313-win_amd64.whl", hash = "sha256:6ff1ba153e0740c2ea47d74d015c1a03c3addab1681633be0838103c297b855c", size = 183441, upload-time = "2025-07-29T01:11:04.029Z" }, - { url = "https://files.pythonhosted.org/packages/0e/a5/85855a9ad255edf6be1fcd6e44384daa506a2276ef4f0e6164bc2dd03785/cffi-2.0.0b1-cp313-cp313-win_arm64.whl", hash = "sha256:adbed7d68bc8837eb2c73e01bc284b5af9898e82b6067a6cbffea4f1820626e4", size = 177621, upload-time = "2025-07-29T01:11:05.191Z" }, - { url = "https://files.pythonhosted.org/packages/7a/04/070592956f9818f6ef2c5219410209af08c3b81889da0b36185b535bdb2a/cffi-2.0.0b1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fe8cb43962af8e43facad740930fadc4cf8cdc1e073f59d0f13714711807979f", size = 185398, upload-time = "2025-07-29T01:11:06.337Z" }, - { url = "https://files.pythonhosted.org/packages/f7/68/704fba8db6ece9cb13f48e1c17311f70f49153671e056ae99ea29c549d39/cffi-2.0.0b1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a812e9ab7a0bfef3e89089c0359e631d8521d5efc8d21c7ede3f1568db689920", size = 181540, upload-time = "2025-07-29T01:11:07.4Z" }, - { url = "https://files.pythonhosted.org/packages/aa/f7/5a6f7913430f0e0e5e2ac5b06fd69bb532f1e420404d508936da6117a5b8/cffi-2.0.0b1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bce5ce4790b8347c2d7937312218d0282af344f8a589db163520a02fe8e42281", size = 207806, upload-time = "2025-07-29T01:11:08.543Z" }, - { url = "https://files.pythonhosted.org/packages/79/78/870845b72b8017717826bbfca874115e2dac88b8bf204298edc946691817/cffi-2.0.0b1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:39eedbed09879f6d1591ad155afcc162aa11ebf3271215339b4aef3df5631573", size = 206531, upload-time = "2025-07-29T01:11:09.803Z" }, - { url = "https://files.pythonhosted.org/packages/a7/f4/d65f9a303b97453f19588fd7d336c6e527b8ee9fc3b956296d63c6af5562/cffi-2.0.0b1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7dfd6f8f57e812f3175aa0d4d36ed797b6ff35f7cdfefea05417569b543ddc94", size = 220766, upload-time = "2025-07-29T01:11:10.978Z" }, - { url = "https://files.pythonhosted.org/packages/a1/09/85fa0b2841a16d2c3571661a9c4bb53441e195dda2413cfeab05b9726e56/cffi-2.0.0b1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:782f60714ea2935e5391a0f69ad4705624cdc86243b18dcfafd08565c28e89bd", size = 219317, upload-time = "2025-07-29T01:11:12.148Z" }, - { url = "https://files.pythonhosted.org/packages/75/87/91037b0c976babf124760cae2e0a0ca0ce18f02b5b34146421feecd6558d/cffi-2.0.0b1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f2ebc97ba03b26e9b6b048b6c3981165126905cb20564fbf6584f5e072a1c189", size = 222874, upload-time = "2025-07-29T01:11:13.346Z" }, - { url = "https://files.pythonhosted.org/packages/56/53/1c871477e707c001c30537e8f4807341f1d3b40bd6f094cf054864b41dc6/cffi-2.0.0b1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fba9546b80f3b275f04915ffbca7b75aa22a353c4f6410469fb1d8c340ec1c31", size = 220973, upload-time = "2025-07-29T01:11:14.528Z" }, - { url = "https://files.pythonhosted.org/packages/81/c7/4cb50e2e7623a41d9416dc8d7d043ba3a69f2424209a1e04c28833216f90/cffi-2.0.0b1-cp314-cp314-win32.whl", hash = "sha256:339e853c75f69c726b1a85f2217db6880422f915770679c47150eea895e02b46", size = 175360, upload-time = "2025-07-29T01:11:31.19Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ba/d0fb6fc597d2d11b77294626c51d3f01f9475c4ec3462687fef5244f09be/cffi-2.0.0b1-cp314-cp314-win_amd64.whl", hash = "sha256:856eb353a42b04d02b0633c71123276710a5390e92a27fbd2446864ca7d27923", size = 185681, upload-time = "2025-07-29T01:11:32.464Z" }, - { url = "https://files.pythonhosted.org/packages/24/0f/12390e59c1cb01a161d24f5ef73f15110c6c8f1e51ba8a42411d3faf5d58/cffi-2.0.0b1-cp314-cp314-win_arm64.whl", hash = "sha256:9e23ac717e8b3767c80198d483c743fe596b055a6e29ef34f9d8cdf61f941f2f", size = 180386, upload-time = "2025-07-29T01:11:33.648Z" }, - { url = "https://files.pythonhosted.org/packages/48/6a/87dfc25b45dcae6e05e342f29ac384b5847256c06b99b5e226d59549bf21/cffi-2.0.0b1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:e227627762046204df31c589d7406540778d05622e395d41fc68b7895d40c174", size = 188831, upload-time = "2025-07-29T01:11:15.772Z" }, - { url = "https://files.pythonhosted.org/packages/9d/d9/4c6e38b9837e053f096007c37586be4dc6201664103db3a401618f37159e/cffi-2.0.0b1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2355cd38f375906da70a8bad548eb63f65bed43c1044ed075691fa36e8e8315a", size = 185064, upload-time = "2025-07-29T01:11:16.961Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b4/e3797890685586d764c4bc20947e45cdddfa6dec8a635df84a947c7be8f8/cffi-2.0.0b1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14c0ade7949f088615450abf884064b4ef11e8c9917b99d53f12e06cdfd2cd36", size = 209488, upload-time = "2025-07-29T01:11:18.258Z" }, - { url = "https://files.pythonhosted.org/packages/85/51/b91f5e8a30ea6b77a9ede74bab40482a86ec0d4c462ef4bc8f2c0775f969/cffi-2.0.0b1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:765c82d4a73ded03bfea961364f4c57dd6cfe7b0d57b7a2d9b95e2e7bd5de6f7", size = 208670, upload-time = "2025-07-29T01:11:19.753Z" }, - { url = "https://files.pythonhosted.org/packages/12/4c/ced2c206f38bd7cc1124aa8d9b4cbbd6db54a7a9220f889ba35a07b4f4b2/cffi-2.0.0b1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:265666e15da6974e6a74110873321e84c7c2288e379aca44a7df4713325b9be4", size = 222420, upload-time = "2025-07-29T01:11:21.043Z" }, - { url = "https://files.pythonhosted.org/packages/c1/8c/49feb0f27d072d7b4f5fe48407451a697015e6cf3197e144ebc5ed6c361f/cffi-2.0.0b1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d88f849d03c9aa2d7bbd710a0e20266f92bf524396c7fce881cd5a1971447812", size = 221747, upload-time = "2025-07-29T01:11:22.362Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ea/f0b0c31e6445767441e8dad5a3fa267de7ffc5a87ebd13bc0fd2efa76f8f/cffi-2.0.0b1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:853e90e942246f9e098f16baa45896f80675f86ab6447823c4030a67c3cc112d", size = 224491, upload-time = "2025-07-29T01:11:23.95Z" }, - { url = "https://files.pythonhosted.org/packages/dc/6e/e5349ac9bf812e9a44914f699999c960c045bbd12b63358a4b583ab6ad85/cffi-2.0.0b1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3b8aee0176d80781a21855832c411cfd3126c34966650693ec1245f0b756498b", size = 223484, upload-time = "2025-07-29T01:11:25.266Z" }, - { url = "https://files.pythonhosted.org/packages/f5/11/b2a10765c287d368f87dd57e2840876609418d4bb2ea6cfc56d05c8cb8e0/cffi-2.0.0b1-cp314-cp314t-win32.whl", hash = "sha256:2da933859e1465a08f36d88e0452194da27b9ff0813e5ba49f02c544682d40e0", size = 180528, upload-time = "2025-07-29T01:11:26.968Z" }, - { url = "https://files.pythonhosted.org/packages/41/e8/b7a5be3b8c2d07627e6c007628cdd58c26b18b27ca110334c375d39c1665/cffi-2.0.0b1-cp314-cp314t-win_amd64.whl", hash = "sha256:53fbcfdb35760bc6fb68096632d29700bcf37fd0d71922dcc577eb6193fc6edc", size = 191764, upload-time = "2025-07-29T01:11:28.464Z" }, - { url = "https://files.pythonhosted.org/packages/1b/f5/5cec5a3462fe50687acf04f820b96f490a2c28acd7857472607839ba2712/cffi-2.0.0b1-cp314-cp314t-win_arm64.whl", hash = "sha256:505bec438236c623d7cfd8cc740598611a1d4883a629a0e33eb9e3c2dcd81b04", size = 183450, upload-time = "2025-07-29T01:11:29.941Z" }, +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, + { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, + { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, + { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, + { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, ] [[package]] @@ -674,77 +646,77 @@ wheels = [ [[package]] name = "coverage" -version = "7.10.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/61/83/153f54356c7c200013a752ce1ed5448573dca546ce125801afca9e1ac1a4/coverage-7.10.5.tar.gz", hash = "sha256:f2e57716a78bc3ae80b2207be0709a3b2b63b9f2dcf9740ee6ac03588a2015b6", size = 821662, upload-time = "2025-08-23T14:42:44.78Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/f2/336d34d2fc1291ca7c18eeb46f64985e6cef5a1a7ef6d9c23720c6527289/coverage-7.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c177e6ffe2ebc7c410785307758ee21258aa8e8092b44d09a2da767834f075f2", size = 216890, upload-time = "2025-08-23T14:40:43.627Z" }, - { url = "https://files.pythonhosted.org/packages/39/ea/92448b07cc1cf2b429d0ce635f59cf0c626a5d8de21358f11e92174ff2a6/coverage-7.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:14d6071c51ad0f703d6440827eaa46386169b5fdced42631d5a5ac419616046f", size = 217287, upload-time = "2025-08-23T14:40:45.214Z" }, - { url = "https://files.pythonhosted.org/packages/96/ba/ad5b36537c5179c808d0ecdf6e4aa7630b311b3c12747ad624dcd43a9b6b/coverage-7.10.5-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:61f78c7c3bc272a410c5ae3fde7792b4ffb4acc03d35a7df73ca8978826bb7ab", size = 247683, upload-time = "2025-08-23T14:40:46.791Z" }, - { url = "https://files.pythonhosted.org/packages/28/e5/fe3bbc8d097029d284b5fb305b38bb3404895da48495f05bff025df62770/coverage-7.10.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f39071caa126f69d63f99b324fb08c7b1da2ec28cbb1fe7b5b1799926492f65c", size = 249614, upload-time = "2025-08-23T14:40:48.082Z" }, - { url = "https://files.pythonhosted.org/packages/69/9c/a1c89a8c8712799efccb32cd0a1ee88e452f0c13a006b65bb2271f1ac767/coverage-7.10.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343a023193f04d46edc46b2616cdbee68c94dd10208ecd3adc56fcc54ef2baa1", size = 251719, upload-time = "2025-08-23T14:40:49.349Z" }, - { url = "https://files.pythonhosted.org/packages/e9/be/5576b5625865aa95b5633315f8f4142b003a70c3d96e76f04487c3b5cc95/coverage-7.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:585ffe93ae5894d1ebdee69fc0b0d4b7c75d8007983692fb300ac98eed146f78", size = 249411, upload-time = "2025-08-23T14:40:50.624Z" }, - { url = "https://files.pythonhosted.org/packages/94/0a/e39a113d4209da0dbbc9385608cdb1b0726a4d25f78672dc51c97cfea80f/coverage-7.10.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0ef4e66f006ed181df29b59921bd8fc7ed7cd6a9289295cd8b2824b49b570df", size = 247466, upload-time = "2025-08-23T14:40:52.362Z" }, - { url = "https://files.pythonhosted.org/packages/40/cb/aebb2d8c9e3533ee340bea19b71c5b76605a0268aa49808e26fe96ec0a07/coverage-7.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eb7b0bbf7cc1d0453b843eca7b5fa017874735bef9bfdfa4121373d2cc885ed6", size = 248104, upload-time = "2025-08-23T14:40:54.064Z" }, - { url = "https://files.pythonhosted.org/packages/08/e6/26570d6ccce8ff5de912cbfd268e7f475f00597cb58da9991fa919c5e539/coverage-7.10.5-cp311-cp311-win32.whl", hash = "sha256:1d043a8a06987cc0c98516e57c4d3fc2c1591364831e9deb59c9e1b4937e8caf", size = 219327, upload-time = "2025-08-23T14:40:55.424Z" }, - { url = "https://files.pythonhosted.org/packages/79/79/5f48525e366e518b36e66167e3b6e5db6fd54f63982500c6a5abb9d3dfbd/coverage-7.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:fefafcca09c3ac56372ef64a40f5fe17c5592fab906e0fdffd09543f3012ba50", size = 220213, upload-time = "2025-08-23T14:40:56.724Z" }, - { url = "https://files.pythonhosted.org/packages/40/3c/9058128b7b0bf333130c320b1eb1ae485623014a21ee196d68f7737f8610/coverage-7.10.5-cp311-cp311-win_arm64.whl", hash = "sha256:7e78b767da8b5fc5b2faa69bb001edafcd6f3995b42a331c53ef9572c55ceb82", size = 218893, upload-time = "2025-08-23T14:40:58.011Z" }, - { url = "https://files.pythonhosted.org/packages/27/8e/40d75c7128f871ea0fd829d3e7e4a14460cad7c3826e3b472e6471ad05bd/coverage-7.10.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c2d05c7e73c60a4cecc7d9b60dbfd603b4ebc0adafaef371445b47d0f805c8a9", size = 217077, upload-time = "2025-08-23T14:40:59.329Z" }, - { url = "https://files.pythonhosted.org/packages/18/a8/f333f4cf3fb5477a7f727b4d603a2eb5c3c5611c7fe01329c2e13b23b678/coverage-7.10.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:32ddaa3b2c509778ed5373b177eb2bf5662405493baeff52278a0b4f9415188b", size = 217310, upload-time = "2025-08-23T14:41:00.628Z" }, - { url = "https://files.pythonhosted.org/packages/ec/2c/fbecd8381e0a07d1547922be819b4543a901402f63930313a519b937c668/coverage-7.10.5-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dd382410039fe062097aa0292ab6335a3f1e7af7bba2ef8d27dcda484918f20c", size = 248802, upload-time = "2025-08-23T14:41:02.012Z" }, - { url = "https://files.pythonhosted.org/packages/3f/bc/1011da599b414fb6c9c0f34086736126f9ff71f841755786a6b87601b088/coverage-7.10.5-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7fa22800f3908df31cea6fb230f20ac49e343515d968cc3a42b30d5c3ebf9b5a", size = 251550, upload-time = "2025-08-23T14:41:03.438Z" }, - { url = "https://files.pythonhosted.org/packages/4c/6f/b5c03c0c721c067d21bc697accc3642f3cef9f087dac429c918c37a37437/coverage-7.10.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f366a57ac81f5e12797136552f5b7502fa053c861a009b91b80ed51f2ce651c6", size = 252684, upload-time = "2025-08-23T14:41:04.85Z" }, - { url = "https://files.pythonhosted.org/packages/f9/50/d474bc300ebcb6a38a1047d5c465a227605d6473e49b4e0d793102312bc5/coverage-7.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1dc8f1980a272ad4a6c84cba7981792344dad33bf5869361576b7aef42733a", size = 250602, upload-time = "2025-08-23T14:41:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/4a/2d/548c8e04249cbba3aba6bd799efdd11eee3941b70253733f5d355d689559/coverage-7.10.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2285c04ee8676f7938b02b4936d9b9b672064daab3187c20f73a55f3d70e6b4a", size = 248724, upload-time = "2025-08-23T14:41:08.429Z" }, - { url = "https://files.pythonhosted.org/packages/e2/96/a7c3c0562266ac39dcad271d0eec8fc20ab576e3e2f64130a845ad2a557b/coverage-7.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c2492e4dd9daab63f5f56286f8a04c51323d237631eb98505d87e4c4ff19ec34", size = 250158, upload-time = "2025-08-23T14:41:09.749Z" }, - { url = "https://files.pythonhosted.org/packages/f3/75/74d4be58c70c42ef0b352d597b022baf12dbe2b43e7cb1525f56a0fb1d4b/coverage-7.10.5-cp312-cp312-win32.whl", hash = "sha256:38a9109c4ee8135d5df5505384fc2f20287a47ccbe0b3f04c53c9a1989c2bbaf", size = 219493, upload-time = "2025-08-23T14:41:11.095Z" }, - { url = "https://files.pythonhosted.org/packages/4f/08/364e6012d1d4d09d1e27437382967efed971d7613f94bca9add25f0c1f2b/coverage-7.10.5-cp312-cp312-win_amd64.whl", hash = "sha256:6b87f1ad60b30bc3c43c66afa7db6b22a3109902e28c5094957626a0143a001f", size = 220302, upload-time = "2025-08-23T14:41:12.449Z" }, - { url = "https://files.pythonhosted.org/packages/db/d5/7c8a365e1f7355c58af4fe5faf3f90cc8e587590f5854808d17ccb4e7077/coverage-7.10.5-cp312-cp312-win_arm64.whl", hash = "sha256:672a6c1da5aea6c629819a0e1461e89d244f78d7b60c424ecf4f1f2556c041d8", size = 218936, upload-time = "2025-08-23T14:41:13.872Z" }, - { url = "https://files.pythonhosted.org/packages/9f/08/4166ecfb60ba011444f38a5a6107814b80c34c717bc7a23be0d22e92ca09/coverage-7.10.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ef3b83594d933020f54cf65ea1f4405d1f4e41a009c46df629dd964fcb6e907c", size = 217106, upload-time = "2025-08-23T14:41:15.268Z" }, - { url = "https://files.pythonhosted.org/packages/25/d7/b71022408adbf040a680b8c64bf6ead3be37b553e5844f7465643979f7ca/coverage-7.10.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2b96bfdf7c0ea9faebce088a3ecb2382819da4fbc05c7b80040dbc428df6af44", size = 217353, upload-time = "2025-08-23T14:41:16.656Z" }, - { url = "https://files.pythonhosted.org/packages/74/68/21e0d254dbf8972bb8dd95e3fe7038f4be037ff04ba47d6d1b12b37510ba/coverage-7.10.5-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:63df1fdaffa42d914d5c4d293e838937638bf75c794cf20bee12978fc8c4e3bc", size = 248350, upload-time = "2025-08-23T14:41:18.128Z" }, - { url = "https://files.pythonhosted.org/packages/90/65/28752c3a896566ec93e0219fc4f47ff71bd2b745f51554c93e8dcb659796/coverage-7.10.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8002dc6a049aac0e81ecec97abfb08c01ef0c1fbf962d0c98da3950ace89b869", size = 250955, upload-time = "2025-08-23T14:41:19.577Z" }, - { url = "https://files.pythonhosted.org/packages/a5/eb/ca6b7967f57f6fef31da8749ea20417790bb6723593c8cd98a987be20423/coverage-7.10.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63d4bb2966d6f5f705a6b0c6784c8969c468dbc4bcf9d9ded8bff1c7e092451f", size = 252230, upload-time = "2025-08-23T14:41:20.959Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/17a411b2a2a18f8b8c952aa01c00f9284a1fbc677c68a0003b772ea89104/coverage-7.10.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1f672efc0731a6846b157389b6e6d5d5e9e59d1d1a23a5c66a99fd58339914d5", size = 250387, upload-time = "2025-08-23T14:41:22.644Z" }, - { url = "https://files.pythonhosted.org/packages/c7/89/97a9e271188c2fbb3db82235c33980bcbc733da7da6065afbaa1d685a169/coverage-7.10.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3f39cef43d08049e8afc1fde4a5da8510fc6be843f8dea350ee46e2a26b2f54c", size = 248280, upload-time = "2025-08-23T14:41:24.061Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c6/0ad7d0137257553eb4706b4ad6180bec0a1b6a648b092c5bbda48d0e5b2c/coverage-7.10.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2968647e3ed5a6c019a419264386b013979ff1fb67dd11f5c9886c43d6a31fc2", size = 249894, upload-time = "2025-08-23T14:41:26.165Z" }, - { url = "https://files.pythonhosted.org/packages/84/56/fb3aba936addb4c9e5ea14f5979393f1c2466b4c89d10591fd05f2d6b2aa/coverage-7.10.5-cp313-cp313-win32.whl", hash = "sha256:0d511dda38595b2b6934c2b730a1fd57a3635c6aa2a04cb74714cdfdd53846f4", size = 219536, upload-time = "2025-08-23T14:41:27.694Z" }, - { url = "https://files.pythonhosted.org/packages/fc/54/baacb8f2f74431e3b175a9a2881feaa8feb6e2f187a0e7e3046f3c7742b2/coverage-7.10.5-cp313-cp313-win_amd64.whl", hash = "sha256:9a86281794a393513cf117177fd39c796b3f8e3759bb2764259a2abba5cce54b", size = 220330, upload-time = "2025-08-23T14:41:29.081Z" }, - { url = "https://files.pythonhosted.org/packages/64/8a/82a3788f8e31dee51d350835b23d480548ea8621f3effd7c3ba3f7e5c006/coverage-7.10.5-cp313-cp313-win_arm64.whl", hash = "sha256:cebd8e906eb98bb09c10d1feed16096700b1198d482267f8bf0474e63a7b8d84", size = 218961, upload-time = "2025-08-23T14:41:30.511Z" }, - { url = "https://files.pythonhosted.org/packages/d8/a1/590154e6eae07beee3b111cc1f907c30da6fc8ce0a83ef756c72f3c7c748/coverage-7.10.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0520dff502da5e09d0d20781df74d8189ab334a1e40d5bafe2efaa4158e2d9e7", size = 217819, upload-time = "2025-08-23T14:41:31.962Z" }, - { url = "https://files.pythonhosted.org/packages/0d/ff/436ffa3cfc7741f0973c5c89405307fe39b78dcf201565b934e6616fc4ad/coverage-7.10.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d9cd64aca68f503ed3f1f18c7c9174cbb797baba02ca8ab5112f9d1c0328cd4b", size = 218040, upload-time = "2025-08-23T14:41:33.472Z" }, - { url = "https://files.pythonhosted.org/packages/a0/ca/5787fb3d7820e66273913affe8209c534ca11241eb34ee8c4fd2aaa9dd87/coverage-7.10.5-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0913dd1613a33b13c4f84aa6e3f4198c1a21ee28ccb4f674985c1f22109f0aae", size = 259374, upload-time = "2025-08-23T14:41:34.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/89/21af956843896adc2e64fc075eae3c1cadb97ee0a6960733e65e696f32dd/coverage-7.10.5-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1b7181c0feeb06ed8a02da02792f42f829a7b29990fef52eff257fef0885d760", size = 261551, upload-time = "2025-08-23T14:41:36.333Z" }, - { url = "https://files.pythonhosted.org/packages/e1/96/390a69244ab837e0ac137989277879a084c786cf036c3c4a3b9637d43a89/coverage-7.10.5-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36d42b7396b605f774d4372dd9c49bed71cbabce4ae1ccd074d155709dd8f235", size = 263776, upload-time = "2025-08-23T14:41:38.25Z" }, - { url = "https://files.pythonhosted.org/packages/00/32/cfd6ae1da0a521723349f3129b2455832fc27d3f8882c07e5b6fefdd0da2/coverage-7.10.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b4fdc777e05c4940b297bf47bf7eedd56a39a61dc23ba798e4b830d585486ca5", size = 261326, upload-time = "2025-08-23T14:41:40.343Z" }, - { url = "https://files.pythonhosted.org/packages/4c/c4/bf8d459fb4ce2201e9243ce6c015936ad283a668774430a3755f467b39d1/coverage-7.10.5-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:42144e8e346de44a6f1dbd0a56575dd8ab8dfa7e9007da02ea5b1c30ab33a7db", size = 259090, upload-time = "2025-08-23T14:41:42.106Z" }, - { url = "https://files.pythonhosted.org/packages/f4/5d/a234f7409896468e5539d42234016045e4015e857488b0b5b5f3f3fa5f2b/coverage-7.10.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:66c644cbd7aed8fe266d5917e2c9f65458a51cfe5eeff9c05f15b335f697066e", size = 260217, upload-time = "2025-08-23T14:41:43.591Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ad/87560f036099f46c2ddd235be6476dd5c1d6be6bb57569a9348d43eeecea/coverage-7.10.5-cp313-cp313t-win32.whl", hash = "sha256:2d1b73023854068c44b0c554578a4e1ef1b050ed07cf8b431549e624a29a66ee", size = 220194, upload-time = "2025-08-23T14:41:45.051Z" }, - { url = "https://files.pythonhosted.org/packages/36/a8/04a482594fdd83dc677d4a6c7e2d62135fff5a1573059806b8383fad9071/coverage-7.10.5-cp313-cp313t-win_amd64.whl", hash = "sha256:54a1532c8a642d8cc0bd5a9a51f5a9dcc440294fd06e9dda55e743c5ec1a8f14", size = 221258, upload-time = "2025-08-23T14:41:46.44Z" }, - { url = "https://files.pythonhosted.org/packages/eb/ad/7da28594ab66fe2bc720f1bc9b131e62e9b4c6e39f044d9a48d18429cc21/coverage-7.10.5-cp313-cp313t-win_arm64.whl", hash = "sha256:74d5b63fe3f5f5d372253a4ef92492c11a4305f3550631beaa432fc9df16fcff", size = 219521, upload-time = "2025-08-23T14:41:47.882Z" }, - { url = "https://files.pythonhosted.org/packages/d3/7f/c8b6e4e664b8a95254c35a6c8dd0bf4db201ec681c169aae2f1256e05c85/coverage-7.10.5-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:68c5e0bc5f44f68053369fa0d94459c84548a77660a5f2561c5e5f1e3bed7031", size = 217090, upload-time = "2025-08-23T14:41:49.327Z" }, - { url = "https://files.pythonhosted.org/packages/44/74/3ee14ede30a6e10a94a104d1d0522d5fb909a7c7cac2643d2a79891ff3b9/coverage-7.10.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cf33134ffae93865e32e1e37df043bef15a5e857d8caebc0099d225c579b0fa3", size = 217365, upload-time = "2025-08-23T14:41:50.796Z" }, - { url = "https://files.pythonhosted.org/packages/41/5f/06ac21bf87dfb7620d1f870dfa3c2cae1186ccbcdc50b8b36e27a0d52f50/coverage-7.10.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ad8fa9d5193bafcf668231294241302b5e683a0518bf1e33a9a0dfb142ec3031", size = 248413, upload-time = "2025-08-23T14:41:52.5Z" }, - { url = "https://files.pythonhosted.org/packages/21/bc/cc5bed6e985d3a14228539631573f3863be6a2587381e8bc5fdf786377a1/coverage-7.10.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:146fa1531973d38ab4b689bc764592fe6c2f913e7e80a39e7eeafd11f0ef6db2", size = 250943, upload-time = "2025-08-23T14:41:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/8d/43/6a9fc323c2c75cd80b18d58db4a25dc8487f86dd9070f9592e43e3967363/coverage-7.10.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6013a37b8a4854c478d3219ee8bc2392dea51602dd0803a12d6f6182a0061762", size = 252301, upload-time = "2025-08-23T14:41:56.528Z" }, - { url = "https://files.pythonhosted.org/packages/69/7c/3e791b8845f4cd515275743e3775adb86273576596dc9f02dca37357b4f2/coverage-7.10.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eb90fe20db9c3d930fa2ad7a308207ab5b86bf6a76f54ab6a40be4012d88fcae", size = 250302, upload-time = "2025-08-23T14:41:58.171Z" }, - { url = "https://files.pythonhosted.org/packages/5c/bc/5099c1e1cb0c9ac6491b281babea6ebbf999d949bf4aa8cdf4f2b53505e8/coverage-7.10.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:384b34482272e960c438703cafe63316dfbea124ac62006a455c8410bf2a2262", size = 248237, upload-time = "2025-08-23T14:41:59.703Z" }, - { url = "https://files.pythonhosted.org/packages/7e/51/d346eb750a0b2f1e77f391498b753ea906fde69cc11e4b38dca28c10c88c/coverage-7.10.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:467dc74bd0a1a7de2bedf8deaf6811f43602cb532bd34d81ffd6038d6d8abe99", size = 249726, upload-time = "2025-08-23T14:42:01.343Z" }, - { url = "https://files.pythonhosted.org/packages/a3/85/eebcaa0edafe427e93286b94f56ea7e1280f2c49da0a776a6f37e04481f9/coverage-7.10.5-cp314-cp314-win32.whl", hash = "sha256:556d23d4e6393ca898b2e63a5bca91e9ac2d5fb13299ec286cd69a09a7187fde", size = 219825, upload-time = "2025-08-23T14:42:03.263Z" }, - { url = "https://files.pythonhosted.org/packages/3c/f7/6d43e037820742603f1e855feb23463979bf40bd27d0cde1f761dcc66a3e/coverage-7.10.5-cp314-cp314-win_amd64.whl", hash = "sha256:f4446a9547681533c8fa3e3c6cf62121eeee616e6a92bd9201c6edd91beffe13", size = 220618, upload-time = "2025-08-23T14:42:05.037Z" }, - { url = "https://files.pythonhosted.org/packages/4a/b0/ed9432e41424c51509d1da603b0393404b828906236fb87e2c8482a93468/coverage-7.10.5-cp314-cp314-win_arm64.whl", hash = "sha256:5e78bd9cf65da4c303bf663de0d73bf69f81e878bf72a94e9af67137c69b9fe9", size = 219199, upload-time = "2025-08-23T14:42:06.662Z" }, - { url = "https://files.pythonhosted.org/packages/2f/54/5a7ecfa77910f22b659c820f67c16fc1e149ed132ad7117f0364679a8fa9/coverage-7.10.5-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:5661bf987d91ec756a47c7e5df4fbcb949f39e32f9334ccd3f43233bbb65e508", size = 217833, upload-time = "2025-08-23T14:42:08.262Z" }, - { url = "https://files.pythonhosted.org/packages/4e/0e/25672d917cc57857d40edf38f0b867fb9627115294e4f92c8fcbbc18598d/coverage-7.10.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a46473129244db42a720439a26984f8c6f834762fc4573616c1f37f13994b357", size = 218048, upload-time = "2025-08-23T14:42:10.247Z" }, - { url = "https://files.pythonhosted.org/packages/cb/7c/0b2b4f1c6f71885d4d4b2b8608dcfc79057adb7da4143eb17d6260389e42/coverage-7.10.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1f64b8d3415d60f24b058b58d859e9512624bdfa57a2d1f8aff93c1ec45c429b", size = 259549, upload-time = "2025-08-23T14:42:11.811Z" }, - { url = "https://files.pythonhosted.org/packages/94/73/abb8dab1609abec7308d83c6aec547944070526578ee6c833d2da9a0ad42/coverage-7.10.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:44d43de99a9d90b20e0163f9770542357f58860a26e24dc1d924643bd6aa7cb4", size = 261715, upload-time = "2025-08-23T14:42:13.505Z" }, - { url = "https://files.pythonhosted.org/packages/0b/d1/abf31de21ec92731445606b8d5e6fa5144653c2788758fcf1f47adb7159a/coverage-7.10.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a931a87e5ddb6b6404e65443b742cb1c14959622777f2a4efd81fba84f5d91ba", size = 263969, upload-time = "2025-08-23T14:42:15.422Z" }, - { url = "https://files.pythonhosted.org/packages/9c/b3/ef274927f4ebede96056173b620db649cc9cb746c61ffc467946b9d0bc67/coverage-7.10.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9559b906a100029274448f4c8b8b0a127daa4dade5661dfd821b8c188058842", size = 261408, upload-time = "2025-08-23T14:42:16.971Z" }, - { url = "https://files.pythonhosted.org/packages/20/fc/83ca2812be616d69b4cdd4e0c62a7bc526d56875e68fd0f79d47c7923584/coverage-7.10.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b08801e25e3b4526ef9ced1aa29344131a8f5213c60c03c18fe4c6170ffa2874", size = 259168, upload-time = "2025-08-23T14:42:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/fc/4f/e0779e5716f72d5c9962e709d09815d02b3b54724e38567308304c3fc9df/coverage-7.10.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ed9749bb8eda35f8b636fb7632f1c62f735a236a5d4edadd8bbcc5ea0542e732", size = 260317, upload-time = "2025-08-23T14:42:20.005Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fe/4247e732f2234bb5eb9984a0888a70980d681f03cbf433ba7b48f08ca5d5/coverage-7.10.5-cp314-cp314t-win32.whl", hash = "sha256:609b60d123fc2cc63ccee6d17e4676699075db72d14ac3c107cc4976d516f2df", size = 220600, upload-time = "2025-08-23T14:42:22.027Z" }, - { url = "https://files.pythonhosted.org/packages/a7/a0/f294cff6d1034b87839987e5b6ac7385bec599c44d08e0857ac7f164ad0c/coverage-7.10.5-cp314-cp314t-win_amd64.whl", hash = "sha256:0666cf3d2c1626b5a3463fd5b05f5e21f99e6aec40a3192eee4d07a15970b07f", size = 221714, upload-time = "2025-08-23T14:42:23.616Z" }, - { url = "https://files.pythonhosted.org/packages/23/18/fa1afdc60b5528d17416df440bcbd8fd12da12bfea9da5b6ae0f7a37d0f7/coverage-7.10.5-cp314-cp314t-win_arm64.whl", hash = "sha256:bc85eb2d35e760120540afddd3044a5bf69118a91a296a8b3940dfc4fdcfe1e2", size = 219735, upload-time = "2025-08-23T14:42:25.156Z" }, - { url = "https://files.pythonhosted.org/packages/08/b6/fff6609354deba9aeec466e4bcaeb9d1ed3e5d60b14b57df2a36fb2273f2/coverage-7.10.5-py3-none-any.whl", hash = "sha256:0be24d35e4db1d23d0db5c0f6a74a962e2ec83c426b5cac09f4234aadef38e4a", size = 208736, upload-time = "2025-08-23T14:42:43.145Z" }, +version = "7.10.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/14/70/025b179c993f019105b79575ac6edb5e084fb0f0e63f15cdebef4e454fb5/coverage-7.10.6.tar.gz", hash = "sha256:f644a3ae5933a552a29dbb9aa2f90c677a875f80ebea028e5a52a4f429044b90", size = 823736, upload-time = "2025-08-29T15:35:16.668Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/16/2bea27e212c4980753d6d563a0803c150edeaaddb0771a50d2afc410a261/coverage-7.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c706db3cabb7ceef779de68270150665e710b46d56372455cd741184f3868d8f", size = 217129, upload-time = "2025-08-29T15:33:13.575Z" }, + { url = "https://files.pythonhosted.org/packages/2a/51/e7159e068831ab37e31aac0969d47b8c5ee25b7d307b51e310ec34869315/coverage-7.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e0c38dc289e0508ef68ec95834cb5d2e96fdbe792eaccaa1bccac3966bbadcc", size = 217532, upload-time = "2025-08-29T15:33:14.872Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c0/246ccbea53d6099325d25cd208df94ea435cd55f0db38099dd721efc7a1f/coverage-7.10.6-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:752a3005a1ded28f2f3a6e8787e24f28d6abe176ca64677bcd8d53d6fe2ec08a", size = 247931, upload-time = "2025-08-29T15:33:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fb/7435ef8ab9b2594a6e3f58505cc30e98ae8b33265d844007737946c59389/coverage-7.10.6-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:689920ecfd60f992cafca4f5477d55720466ad2c7fa29bb56ac8d44a1ac2b47a", size = 249864, upload-time = "2025-08-29T15:33:17.434Z" }, + { url = "https://files.pythonhosted.org/packages/51/f8/d9d64e8da7bcddb094d511154824038833c81e3a039020a9d6539bf303e9/coverage-7.10.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec98435796d2624d6905820a42f82149ee9fc4f2d45c2c5bc5a44481cc50db62", size = 251969, upload-time = "2025-08-29T15:33:18.822Z" }, + { url = "https://files.pythonhosted.org/packages/43/28/c43ba0ef19f446d6463c751315140d8f2a521e04c3e79e5c5fe211bfa430/coverage-7.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b37201ce4a458c7a758ecc4efa92fa8ed783c66e0fa3c42ae19fc454a0792153", size = 249659, upload-time = "2025-08-29T15:33:20.407Z" }, + { url = "https://files.pythonhosted.org/packages/79/3e/53635bd0b72beaacf265784508a0b386defc9ab7fad99ff95f79ce9db555/coverage-7.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2904271c80898663c810a6b067920a61dd8d38341244a3605bd31ab55250dad5", size = 247714, upload-time = "2025-08-29T15:33:21.751Z" }, + { url = "https://files.pythonhosted.org/packages/4c/55/0964aa87126624e8c159e32b0bc4e84edef78c89a1a4b924d28dd8265625/coverage-7.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5aea98383463d6e1fa4e95416d8de66f2d0cb588774ee20ae1b28df826bcb619", size = 248351, upload-time = "2025-08-29T15:33:23.105Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ab/6cfa9dc518c6c8e14a691c54e53a9433ba67336c760607e299bfcf520cb1/coverage-7.10.6-cp311-cp311-win32.whl", hash = "sha256:e3fb1fa01d3598002777dd259c0c2e6d9d5e10e7222976fc8e03992f972a2cba", size = 219562, upload-time = "2025-08-29T15:33:24.717Z" }, + { url = "https://files.pythonhosted.org/packages/5b/18/99b25346690cbc55922e7cfef06d755d4abee803ef335baff0014268eff4/coverage-7.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:f35ed9d945bece26553d5b4c8630453169672bea0050a564456eb88bdffd927e", size = 220453, upload-time = "2025-08-29T15:33:26.482Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ed/81d86648a07ccb124a5cf1f1a7788712b8d7216b593562683cd5c9b0d2c1/coverage-7.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:99e1a305c7765631d74b98bf7dbf54eeea931f975e80f115437d23848ee8c27c", size = 219127, upload-time = "2025-08-29T15:33:27.777Z" }, + { url = "https://files.pythonhosted.org/packages/26/06/263f3305c97ad78aab066d116b52250dd316e74fcc20c197b61e07eb391a/coverage-7.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b2dd6059938063a2c9fee1af729d4f2af28fd1a545e9b7652861f0d752ebcea", size = 217324, upload-time = "2025-08-29T15:33:29.06Z" }, + { url = "https://files.pythonhosted.org/packages/e9/60/1e1ded9a4fe80d843d7d53b3e395c1db3ff32d6c301e501f393b2e6c1c1f/coverage-7.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:388d80e56191bf846c485c14ae2bc8898aa3124d9d35903fef7d907780477634", size = 217560, upload-time = "2025-08-29T15:33:30.748Z" }, + { url = "https://files.pythonhosted.org/packages/b8/25/52136173c14e26dfed8b106ed725811bb53c30b896d04d28d74cb64318b3/coverage-7.10.6-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:90cb5b1a4670662719591aa92d0095bb41714970c0b065b02a2610172dbf0af6", size = 249053, upload-time = "2025-08-29T15:33:32.041Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1d/ae25a7dc58fcce8b172d42ffe5313fc267afe61c97fa872b80ee72d9515a/coverage-7.10.6-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:961834e2f2b863a0e14260a9a273aff07ff7818ab6e66d2addf5628590c628f9", size = 251802, upload-time = "2025-08-29T15:33:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/f5/7a/1f561d47743710fe996957ed7c124b421320f150f1d38523d8d9102d3e2a/coverage-7.10.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf9a19f5012dab774628491659646335b1928cfc931bf8d97b0d5918dd58033c", size = 252935, upload-time = "2025-08-29T15:33:34.909Z" }, + { url = "https://files.pythonhosted.org/packages/6c/ad/8b97cd5d28aecdfde792dcbf646bac141167a5cacae2cd775998b45fabb5/coverage-7.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99c4283e2a0e147b9c9cc6bc9c96124de9419d6044837e9799763a0e29a7321a", size = 250855, upload-time = "2025-08-29T15:33:36.922Z" }, + { url = "https://files.pythonhosted.org/packages/33/6a/95c32b558d9a61858ff9d79580d3877df3eb5bc9eed0941b1f187c89e143/coverage-7.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:282b1b20f45df57cc508c1e033403f02283adfb67d4c9c35a90281d81e5c52c5", size = 248974, upload-time = "2025-08-29T15:33:38.175Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9c/8ce95dee640a38e760d5b747c10913e7a06554704d60b41e73fdea6a1ffd/coverage-7.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cdbe264f11afd69841bd8c0d83ca10b5b32853263ee62e6ac6a0ab63895f972", size = 250409, upload-time = "2025-08-29T15:33:39.447Z" }, + { url = "https://files.pythonhosted.org/packages/04/12/7a55b0bdde78a98e2eb2356771fd2dcddb96579e8342bb52aa5bc52e96f0/coverage-7.10.6-cp312-cp312-win32.whl", hash = "sha256:a517feaf3a0a3eca1ee985d8373135cfdedfbba3882a5eab4362bda7c7cf518d", size = 219724, upload-time = "2025-08-29T15:33:41.172Z" }, + { url = "https://files.pythonhosted.org/packages/36/4a/32b185b8b8e327802c9efce3d3108d2fe2d9d31f153a0f7ecfd59c773705/coverage-7.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:856986eadf41f52b214176d894a7de05331117f6035a28ac0016c0f63d887629", size = 220536, upload-time = "2025-08-29T15:33:42.524Z" }, + { url = "https://files.pythonhosted.org/packages/08/3a/d5d8dc703e4998038c3099eaf77adddb00536a3cec08c8dcd556a36a3eb4/coverage-7.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:acf36b8268785aad739443fa2780c16260ee3fa09d12b3a70f772ef100939d80", size = 219171, upload-time = "2025-08-29T15:33:43.974Z" }, + { url = "https://files.pythonhosted.org/packages/bd/e7/917e5953ea29a28c1057729c1d5af9084ab6d9c66217523fd0e10f14d8f6/coverage-7.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ffea0575345e9ee0144dfe5701aa17f3ba546f8c3bb48db62ae101afb740e7d6", size = 217351, upload-time = "2025-08-29T15:33:45.438Z" }, + { url = "https://files.pythonhosted.org/packages/eb/86/2e161b93a4f11d0ea93f9bebb6a53f113d5d6e416d7561ca41bb0a29996b/coverage-7.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d91d7317cde40a1c249d6b7382750b7e6d86fad9d8eaf4fa3f8f44cf171e80", size = 217600, upload-time = "2025-08-29T15:33:47.269Z" }, + { url = "https://files.pythonhosted.org/packages/0e/66/d03348fdd8df262b3a7fb4ee5727e6e4936e39e2f3a842e803196946f200/coverage-7.10.6-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e23dd5408fe71a356b41baa82892772a4cefcf758f2ca3383d2aa39e1b7a003", size = 248600, upload-time = "2025-08-29T15:33:48.953Z" }, + { url = "https://files.pythonhosted.org/packages/73/dd/508420fb47d09d904d962f123221bc249f64b5e56aa93d5f5f7603be475f/coverage-7.10.6-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f3f56e4cb573755e96a16501a98bf211f100463d70275759e73f3cbc00d4f27", size = 251206, upload-time = "2025-08-29T15:33:50.697Z" }, + { url = "https://files.pythonhosted.org/packages/e9/1f/9020135734184f439da85c70ea78194c2730e56c2d18aee6e8ff1719d50d/coverage-7.10.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4a1d897bbbe7339946ffa2fe60c10cc81c43fab8b062d3fcb84188688174a4", size = 252478, upload-time = "2025-08-29T15:33:52.303Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a4/3d228f3942bb5a2051fde28c136eea23a761177dc4ff4ef54533164ce255/coverage-7.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fd7879082953c156d5b13c74aa6cca37f6a6f4747b39538504c3f9c63d043d", size = 250637, upload-time = "2025-08-29T15:33:53.67Z" }, + { url = "https://files.pythonhosted.org/packages/36/e3/293dce8cdb9a83de971637afc59b7190faad60603b40e32635cbd15fbf61/coverage-7.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:28395ca3f71cd103b8c116333fa9db867f3a3e1ad6a084aa3725ae002b6583bc", size = 248529, upload-time = "2025-08-29T15:33:55.022Z" }, + { url = "https://files.pythonhosted.org/packages/90/26/64eecfa214e80dd1d101e420cab2901827de0e49631d666543d0e53cf597/coverage-7.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61c950fc33d29c91b9e18540e1aed7d9f6787cc870a3e4032493bbbe641d12fc", size = 250143, upload-time = "2025-08-29T15:33:56.386Z" }, + { url = "https://files.pythonhosted.org/packages/3e/70/bd80588338f65ea5b0d97e424b820fb4068b9cfb9597fbd91963086e004b/coverage-7.10.6-cp313-cp313-win32.whl", hash = "sha256:160c00a5e6b6bdf4e5984b0ef21fc860bc94416c41b7df4d63f536d17c38902e", size = 219770, upload-time = "2025-08-29T15:33:58.063Z" }, + { url = "https://files.pythonhosted.org/packages/a7/14/0b831122305abcc1060c008f6c97bbdc0a913ab47d65070a01dc50293c2b/coverage-7.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:628055297f3e2aa181464c3808402887643405573eb3d9de060d81531fa79d32", size = 220566, upload-time = "2025-08-29T15:33:59.766Z" }, + { url = "https://files.pythonhosted.org/packages/83/c6/81a83778c1f83f1a4a168ed6673eeedc205afb562d8500175292ca64b94e/coverage-7.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:df4ec1f8540b0bcbe26ca7dd0f541847cc8a108b35596f9f91f59f0c060bfdd2", size = 219195, upload-time = "2025-08-29T15:34:01.191Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1c/ccccf4bf116f9517275fa85047495515add43e41dfe8e0bef6e333c6b344/coverage-7.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c9a8b7a34a4de3ed987f636f71881cd3b8339f61118b1aa311fbda12741bff0b", size = 218059, upload-time = "2025-08-29T15:34:02.91Z" }, + { url = "https://files.pythonhosted.org/packages/92/97/8a3ceff833d27c7492af4f39d5da6761e9ff624831db9e9f25b3886ddbca/coverage-7.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd5af36092430c2b075cee966719898f2ae87b636cefb85a653f1d0ba5d5393", size = 218287, upload-time = "2025-08-29T15:34:05.106Z" }, + { url = "https://files.pythonhosted.org/packages/92/d8/50b4a32580cf41ff0423777a2791aaf3269ab60c840b62009aec12d3970d/coverage-7.10.6-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0353b0f0850d49ada66fdd7d0c7cdb0f86b900bb9e367024fd14a60cecc1e27", size = 259625, upload-time = "2025-08-29T15:34:06.575Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7e/6a7df5a6fb440a0179d94a348eb6616ed4745e7df26bf2a02bc4db72c421/coverage-7.10.6-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6b9ae13d5d3e8aeca9ca94198aa7b3ebbc5acfada557d724f2a1f03d2c0b0df", size = 261801, upload-time = "2025-08-29T15:34:08.006Z" }, + { url = "https://files.pythonhosted.org/packages/3a/4c/a270a414f4ed5d196b9d3d67922968e768cd971d1b251e1b4f75e9362f75/coverage-7.10.6-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:675824a363cc05781b1527b39dc2587b8984965834a748177ee3c37b64ffeafb", size = 264027, upload-time = "2025-08-29T15:34:09.806Z" }, + { url = "https://files.pythonhosted.org/packages/9c/8b/3210d663d594926c12f373c5370bf1e7c5c3a427519a8afa65b561b9a55c/coverage-7.10.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:692d70ea725f471a547c305f0d0fc6a73480c62fb0da726370c088ab21aed282", size = 261576, upload-time = "2025-08-29T15:34:11.585Z" }, + { url = "https://files.pythonhosted.org/packages/72/d0/e1961eff67e9e1dba3fc5eb7a4caf726b35a5b03776892da8d79ec895775/coverage-7.10.6-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:851430a9a361c7a8484a36126d1d0ff8d529d97385eacc8dfdc9bfc8c2d2cbe4", size = 259341, upload-time = "2025-08-29T15:34:13.159Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/d6478d152cd189b33eac691cba27a40704990ba95de49771285f34a5861e/coverage-7.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d9369a23186d189b2fc95cc08b8160ba242057e887d766864f7adf3c46b2df21", size = 260468, upload-time = "2025-08-29T15:34:14.571Z" }, + { url = "https://files.pythonhosted.org/packages/ed/73/737440247c914a332f0b47f7598535b29965bf305e19bbc22d4c39615d2b/coverage-7.10.6-cp313-cp313t-win32.whl", hash = "sha256:92be86fcb125e9bda0da7806afd29a3fd33fdf58fba5d60318399adf40bf37d0", size = 220429, upload-time = "2025-08-29T15:34:16.394Z" }, + { url = "https://files.pythonhosted.org/packages/bd/76/b92d3214740f2357ef4a27c75a526eb6c28f79c402e9f20a922c295c05e2/coverage-7.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6b3039e2ca459a70c79523d39347d83b73f2f06af5624905eba7ec34d64d80b5", size = 221493, upload-time = "2025-08-29T15:34:17.835Z" }, + { url = "https://files.pythonhosted.org/packages/fc/8e/6dcb29c599c8a1f654ec6cb68d76644fe635513af16e932d2d4ad1e5ac6e/coverage-7.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3fb99d0786fe17b228eab663d16bee2288e8724d26a199c29325aac4b0319b9b", size = 219757, upload-time = "2025-08-29T15:34:19.248Z" }, + { url = "https://files.pythonhosted.org/packages/d3/aa/76cf0b5ec00619ef208da4689281d48b57f2c7fde883d14bf9441b74d59f/coverage-7.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6008a021907be8c4c02f37cdc3ffb258493bdebfeaf9a839f9e71dfdc47b018e", size = 217331, upload-time = "2025-08-29T15:34:20.846Z" }, + { url = "https://files.pythonhosted.org/packages/65/91/8e41b8c7c505d398d7730206f3cbb4a875a35ca1041efc518051bfce0f6b/coverage-7.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5e75e37f23eb144e78940b40395b42f2321951206a4f50e23cfd6e8a198d3ceb", size = 217607, upload-time = "2025-08-29T15:34:22.433Z" }, + { url = "https://files.pythonhosted.org/packages/87/7f/f718e732a423d442e6616580a951b8d1ec3575ea48bcd0e2228386805e79/coverage-7.10.6-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0f7cb359a448e043c576f0da00aa8bfd796a01b06aa610ca453d4dde09cc1034", size = 248663, upload-time = "2025-08-29T15:34:24.425Z" }, + { url = "https://files.pythonhosted.org/packages/e6/52/c1106120e6d801ac03e12b5285e971e758e925b6f82ee9b86db3aa10045d/coverage-7.10.6-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c68018e4fc4e14b5668f1353b41ccf4bc83ba355f0e1b3836861c6f042d89ac1", size = 251197, upload-time = "2025-08-29T15:34:25.906Z" }, + { url = "https://files.pythonhosted.org/packages/3d/ec/3a8645b1bb40e36acde9c0609f08942852a4af91a937fe2c129a38f2d3f5/coverage-7.10.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd4b2b0707fc55afa160cd5fc33b27ccbf75ca11d81f4ec9863d5793fc6df56a", size = 252551, upload-time = "2025-08-29T15:34:27.337Z" }, + { url = "https://files.pythonhosted.org/packages/a1/70/09ecb68eeb1155b28a1d16525fd3a9b65fbe75337311a99830df935d62b6/coverage-7.10.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cec13817a651f8804a86e4f79d815b3b28472c910e099e4d5a0e8a3b6a1d4cb", size = 250553, upload-time = "2025-08-29T15:34:29.065Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/47df374b893fa812e953b5bc93dcb1427a7b3d7a1a7d2db33043d17f74b9/coverage-7.10.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f2a6a8e06bbda06f78739f40bfb56c45d14eb8249d0f0ea6d4b3d48e1f7c695d", size = 248486, upload-time = "2025-08-29T15:34:30.897Z" }, + { url = "https://files.pythonhosted.org/packages/4a/65/9f98640979ecee1b0d1a7164b589de720ddf8100d1747d9bbdb84be0c0fb/coverage-7.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:081b98395ced0d9bcf60ada7661a0b75f36b78b9d7e39ea0790bb4ed8da14747", size = 249981, upload-time = "2025-08-29T15:34:32.365Z" }, + { url = "https://files.pythonhosted.org/packages/1f/55/eeb6603371e6629037f47bd25bef300387257ed53a3c5fdb159b7ac8c651/coverage-7.10.6-cp314-cp314-win32.whl", hash = "sha256:6937347c5d7d069ee776b2bf4e1212f912a9f1f141a429c475e6089462fcecc5", size = 220054, upload-time = "2025-08-29T15:34:34.124Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/a0912b7611bc35412e919a2cd59ae98e7ea3b475e562668040a43fb27897/coverage-7.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:adec1d980fa07e60b6ef865f9e5410ba760e4e1d26f60f7e5772c73b9a5b0713", size = 220851, upload-time = "2025-08-29T15:34:35.651Z" }, + { url = "https://files.pythonhosted.org/packages/ef/2d/11880bb8ef80a45338e0b3e0725e4c2d73ffbb4822c29d987078224fd6a5/coverage-7.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:a80f7aef9535442bdcf562e5a0d5a5538ce8abe6bb209cfbf170c462ac2c2a32", size = 219429, upload-time = "2025-08-29T15:34:37.16Z" }, + { url = "https://files.pythonhosted.org/packages/83/c0/1f00caad775c03a700146f55536ecd097a881ff08d310a58b353a1421be0/coverage-7.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0de434f4fbbe5af4fa7989521c655c8c779afb61c53ab561b64dcee6149e4c65", size = 218080, upload-time = "2025-08-29T15:34:38.919Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c4/b1c5d2bd7cc412cbeb035e257fd06ed4e3e139ac871d16a07434e145d18d/coverage-7.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6e31b8155150c57e5ac43ccd289d079eb3f825187d7c66e755a055d2c85794c6", size = 218293, upload-time = "2025-08-29T15:34:40.425Z" }, + { url = "https://files.pythonhosted.org/packages/3f/07/4468d37c94724bf6ec354e4ec2f205fda194343e3e85fd2e59cec57e6a54/coverage-7.10.6-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:98cede73eb83c31e2118ae8d379c12e3e42736903a8afcca92a7218e1f2903b0", size = 259800, upload-time = "2025-08-29T15:34:41.996Z" }, + { url = "https://files.pythonhosted.org/packages/82/d8/f8fb351be5fee31690cd8da768fd62f1cfab33c31d9f7baba6cd8960f6b8/coverage-7.10.6-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f863c08f4ff6b64fa8045b1e3da480f5374779ef187f07b82e0538c68cb4ff8e", size = 261965, upload-time = "2025-08-29T15:34:43.61Z" }, + { url = "https://files.pythonhosted.org/packages/e8/70/65d4d7cfc75c5c6eb2fed3ee5cdf420fd8ae09c4808723a89a81d5b1b9c3/coverage-7.10.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b38261034fda87be356f2c3f42221fdb4171c3ce7658066ae449241485390d5", size = 264220, upload-time = "2025-08-29T15:34:45.387Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/069df106d19024324cde10e4ec379fe2fb978017d25e97ebee23002fbadf/coverage-7.10.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e93b1476b79eae849dc3872faeb0bf7948fd9ea34869590bc16a2a00b9c82a7", size = 261660, upload-time = "2025-08-29T15:34:47.288Z" }, + { url = "https://files.pythonhosted.org/packages/fc/8a/2974d53904080c5dc91af798b3a54a4ccb99a45595cc0dcec6eb9616a57d/coverage-7.10.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ff8a991f70f4c0cf53088abf1e3886edcc87d53004c7bb94e78650b4d3dac3b5", size = 259417, upload-time = "2025-08-29T15:34:48.779Z" }, + { url = "https://files.pythonhosted.org/packages/30/38/9616a6b49c686394b318974d7f6e08f38b8af2270ce7488e879888d1e5db/coverage-7.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ac765b026c9f33044419cbba1da913cfb82cca1b60598ac1c7a5ed6aac4621a0", size = 260567, upload-time = "2025-08-29T15:34:50.718Z" }, + { url = "https://files.pythonhosted.org/packages/76/16/3ed2d6312b371a8cf804abf4e14895b70e4c3491c6e53536d63fd0958a8d/coverage-7.10.6-cp314-cp314t-win32.whl", hash = "sha256:441c357d55f4936875636ef2cfb3bee36e466dcf50df9afbd398ce79dba1ebb7", size = 220831, upload-time = "2025-08-29T15:34:52.653Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e5/d38d0cb830abede2adb8b147770d2a3d0e7fecc7228245b9b1ae6c24930a/coverage-7.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:073711de3181b2e204e4870ac83a7c4853115b42e9cd4d145f2231e12d670930", size = 221950, upload-time = "2025-08-29T15:34:54.212Z" }, + { url = "https://files.pythonhosted.org/packages/f4/51/e48e550f6279349895b0ffcd6d2a690e3131ba3a7f4eafccc141966d4dea/coverage-7.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:137921f2bac5559334ba66122b753db6dc5d1cf01eb7b64eb412bb0d064ef35b", size = 219969, upload-time = "2025-08-29T15:34:55.83Z" }, + { url = "https://files.pythonhosted.org/packages/44/0c/50db5379b615854b5cf89146f8f5bd1d5a9693d7f3a987e269693521c404/coverage-7.10.6-py3-none-any.whl", hash = "sha256:92c4ecf6bf11b2e85fd4d8204814dc26e6a19f0c9d938c207c5cb0eadfcabbe3", size = 208986, upload-time = "2025-08-29T15:35:14.506Z" }, ] [package.optional-dependencies] @@ -754,52 +726,52 @@ toml = [ [[package]] name = "cryptography" -version = "45.0.6" +version = "45.0.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/0d/d13399c94234ee8f3df384819dc67e0c5ce215fb751d567a55a1f4b028c7/cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719", size = 744949, upload-time = "2025-08-05T23:59:27.93Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/29/2793d178d0eda1ca4a09a7c4e09a5185e75738cc6d526433e8663b460ea6/cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74", size = 7042702, upload-time = "2025-08-05T23:58:23.464Z" }, - { url = "https://files.pythonhosted.org/packages/b3/b6/cabd07410f222f32c8d55486c464f432808abaa1f12af9afcbe8f2f19030/cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f", size = 4206483, upload-time = "2025-08-05T23:58:27.132Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9e/f9c7d36a38b1cfeb1cc74849aabe9bf817990f7603ff6eb485e0d70e0b27/cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf", size = 4429679, upload-time = "2025-08-05T23:58:29.152Z" }, - { url = "https://files.pythonhosted.org/packages/9c/2a/4434c17eb32ef30b254b9e8b9830cee4e516f08b47fdd291c5b1255b8101/cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5", size = 4210553, upload-time = "2025-08-05T23:58:30.596Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1d/09a5df8e0c4b7970f5d1f3aff1b640df6d4be28a64cae970d56c6cf1c772/cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2", size = 3894499, upload-time = "2025-08-05T23:58:32.03Z" }, - { url = "https://files.pythonhosted.org/packages/79/62/120842ab20d9150a9d3a6bdc07fe2870384e82f5266d41c53b08a3a96b34/cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08", size = 4458484, upload-time = "2025-08-05T23:58:33.526Z" }, - { url = "https://files.pythonhosted.org/packages/fd/80/1bc3634d45ddfed0871bfba52cf8f1ad724761662a0c792b97a951fb1b30/cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402", size = 4210281, upload-time = "2025-08-05T23:58:35.445Z" }, - { url = "https://files.pythonhosted.org/packages/7d/fe/ffb12c2d83d0ee625f124880a1f023b5878f79da92e64c37962bbbe35f3f/cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42", size = 4456890, upload-time = "2025-08-05T23:58:36.923Z" }, - { url = "https://files.pythonhosted.org/packages/8c/8e/b3f3fe0dc82c77a0deb5f493b23311e09193f2268b77196ec0f7a36e3f3e/cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05", size = 4333247, upload-time = "2025-08-05T23:58:38.781Z" }, - { url = "https://files.pythonhosted.org/packages/b3/a6/c3ef2ab9e334da27a1d7b56af4a2417d77e7806b2e0f90d6267ce120d2e4/cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453", size = 4565045, upload-time = "2025-08-05T23:58:40.415Z" }, - { url = "https://files.pythonhosted.org/packages/31/c3/77722446b13fa71dddd820a5faab4ce6db49e7e0bf8312ef4192a3f78e2f/cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159", size = 2928923, upload-time = "2025-08-05T23:58:41.919Z" }, - { url = "https://files.pythonhosted.org/packages/38/63/a025c3225188a811b82932a4dcc8457a26c3729d81578ccecbcce2cb784e/cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec", size = 3403805, upload-time = "2025-08-05T23:58:43.792Z" }, - { url = "https://files.pythonhosted.org/packages/5b/af/bcfbea93a30809f126d51c074ee0fac5bd9d57d068edf56c2a73abedbea4/cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0", size = 7020111, upload-time = "2025-08-05T23:58:45.316Z" }, - { url = "https://files.pythonhosted.org/packages/98/c6/ea5173689e014f1a8470899cd5beeb358e22bb3cf5a876060f9d1ca78af4/cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394", size = 4198169, upload-time = "2025-08-05T23:58:47.121Z" }, - { url = "https://files.pythonhosted.org/packages/ba/73/b12995edc0c7e2311ffb57ebd3b351f6b268fed37d93bfc6f9856e01c473/cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9", size = 4421273, upload-time = "2025-08-05T23:58:48.557Z" }, - { url = "https://files.pythonhosted.org/packages/f7/6e/286894f6f71926bc0da67408c853dd9ba953f662dcb70993a59fd499f111/cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3", size = 4199211, upload-time = "2025-08-05T23:58:50.139Z" }, - { url = "https://files.pythonhosted.org/packages/de/34/a7f55e39b9623c5cb571d77a6a90387fe557908ffc44f6872f26ca8ae270/cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3", size = 3883732, upload-time = "2025-08-05T23:58:52.253Z" }, - { url = "https://files.pythonhosted.org/packages/f9/b9/c6d32edbcba0cd9f5df90f29ed46a65c4631c4fbe11187feb9169c6ff506/cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301", size = 4450655, upload-time = "2025-08-05T23:58:53.848Z" }, - { url = "https://files.pythonhosted.org/packages/77/2d/09b097adfdee0227cfd4c699b3375a842080f065bab9014248933497c3f9/cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5", size = 4198956, upload-time = "2025-08-05T23:58:55.209Z" }, - { url = "https://files.pythonhosted.org/packages/55/66/061ec6689207d54effdff535bbdf85cc380d32dd5377173085812565cf38/cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016", size = 4449859, upload-time = "2025-08-05T23:58:56.639Z" }, - { url = "https://files.pythonhosted.org/packages/41/ff/e7d5a2ad2d035e5a2af116e1a3adb4d8fcd0be92a18032917a089c6e5028/cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3", size = 4320254, upload-time = "2025-08-05T23:58:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/82/27/092d311af22095d288f4db89fcaebadfb2f28944f3d790a4cf51fe5ddaeb/cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9", size = 4554815, upload-time = "2025-08-05T23:59:00.283Z" }, - { url = "https://files.pythonhosted.org/packages/7e/01/aa2f4940262d588a8fdf4edabe4cda45854d00ebc6eaac12568b3a491a16/cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02", size = 2912147, upload-time = "2025-08-05T23:59:01.716Z" }, - { url = "https://files.pythonhosted.org/packages/0a/bc/16e0276078c2de3ceef6b5a34b965f4436215efac45313df90d55f0ba2d2/cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b", size = 3390459, upload-time = "2025-08-05T23:59:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/61/69/c252de4ec047ba2f567ecb53149410219577d408c2aea9c989acae7eafce/cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983", size = 3584669, upload-time = "2025-08-05T23:59:15.431Z" }, - { url = "https://files.pythonhosted.org/packages/e3/fe/deea71e9f310a31fe0a6bfee670955152128d309ea2d1c79e2a5ae0f0401/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427", size = 4153022, upload-time = "2025-08-05T23:59:16.954Z" }, - { url = "https://files.pythonhosted.org/packages/60/45/a77452f5e49cb580feedba6606d66ae7b82c128947aa754533b3d1bd44b0/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b", size = 4386802, upload-time = "2025-08-05T23:59:18.55Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b9/a2f747d2acd5e3075fdf5c145c7c3568895daaa38b3b0c960ef830db6cdc/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c", size = 4152706, upload-time = "2025-08-05T23:59:20.044Z" }, - { url = "https://files.pythonhosted.org/packages/81/ec/381b3e8d0685a3f3f304a382aa3dfce36af2d76467da0fd4bb21ddccc7b2/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385", size = 4386740, upload-time = "2025-08-05T23:59:21.525Z" }, - { url = "https://files.pythonhosted.org/packages/0a/76/cf8d69da8d0b5ecb0db406f24a63a3f69ba5e791a11b782aeeefef27ccbb/cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043", size = 3331874, upload-time = "2025-08-05T23:59:23.017Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/a7/35/c495bffc2056f2dadb32434f1feedd79abde2a7f8363e1974afa9c33c7e2/cryptography-45.0.7.tar.gz", hash = "sha256:4b1654dfc64ea479c242508eb8c724044f1e964a47d1d1cacc5132292d851971", size = 744980, upload-time = "2025-09-01T11:15:03.146Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/91/925c0ac74362172ae4516000fe877912e33b5983df735ff290c653de4913/cryptography-45.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3be4f21c6245930688bd9e162829480de027f8bf962ede33d4f8ba7d67a00cee", size = 7041105, upload-time = "2025-09-01T11:13:59.684Z" }, + { url = "https://files.pythonhosted.org/packages/fc/63/43641c5acce3a6105cf8bd5baeceeb1846bb63067d26dae3e5db59f1513a/cryptography-45.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:67285f8a611b0ebc0857ced2081e30302909f571a46bfa7a3cc0ad303fe015c6", size = 4205799, upload-time = "2025-09-01T11:14:02.517Z" }, + { url = "https://files.pythonhosted.org/packages/bc/29/c238dd9107f10bfde09a4d1c52fd38828b1aa353ced11f358b5dd2507d24/cryptography-45.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:577470e39e60a6cd7780793202e63536026d9b8641de011ed9d8174da9ca5339", size = 4430504, upload-time = "2025-09-01T11:14:04.522Z" }, + { url = "https://files.pythonhosted.org/packages/62/62/24203e7cbcc9bd7c94739428cd30680b18ae6b18377ae66075c8e4771b1b/cryptography-45.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4bd3e5c4b9682bc112d634f2c6ccc6736ed3635fc3319ac2bb11d768cc5a00d8", size = 4209542, upload-time = "2025-09-01T11:14:06.309Z" }, + { url = "https://files.pythonhosted.org/packages/cd/e3/e7de4771a08620eef2389b86cd87a2c50326827dea5528feb70595439ce4/cryptography-45.0.7-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:465ccac9d70115cd4de7186e60cfe989de73f7bb23e8a7aa45af18f7412e75bf", size = 3889244, upload-time = "2025-09-01T11:14:08.152Z" }, + { url = "https://files.pythonhosted.org/packages/96/b8/bca71059e79a0bb2f8e4ec61d9c205fbe97876318566cde3b5092529faa9/cryptography-45.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:16ede8a4f7929b4b7ff3642eba2bf79aa1d71f24ab6ee443935c0d269b6bc513", size = 4461975, upload-time = "2025-09-01T11:14:09.755Z" }, + { url = "https://files.pythonhosted.org/packages/58/67/3f5b26937fe1218c40e95ef4ff8d23c8dc05aa950d54200cc7ea5fb58d28/cryptography-45.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8978132287a9d3ad6b54fcd1e08548033cc09dc6aacacb6c004c73c3eb5d3ac3", size = 4209082, upload-time = "2025-09-01T11:14:11.229Z" }, + { url = "https://files.pythonhosted.org/packages/0e/e4/b3e68a4ac363406a56cf7b741eeb80d05284d8c60ee1a55cdc7587e2a553/cryptography-45.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b6a0e535baec27b528cb07a119f321ac024592388c5681a5ced167ae98e9fff3", size = 4460397, upload-time = "2025-09-01T11:14:12.924Z" }, + { url = "https://files.pythonhosted.org/packages/22/49/2c93f3cd4e3efc8cb22b02678c1fad691cff9dd71bb889e030d100acbfe0/cryptography-45.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a24ee598d10befaec178efdff6054bc4d7e883f615bfbcd08126a0f4931c83a6", size = 4337244, upload-time = "2025-09-01T11:14:14.431Z" }, + { url = "https://files.pythonhosted.org/packages/04/19/030f400de0bccccc09aa262706d90f2ec23d56bc4eb4f4e8268d0ddf3fb8/cryptography-45.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:fa26fa54c0a9384c27fcdc905a2fb7d60ac6e47d14bc2692145f2b3b1e2cfdbd", size = 4568862, upload-time = "2025-09-01T11:14:16.185Z" }, + { url = "https://files.pythonhosted.org/packages/29/56/3034a3a353efa65116fa20eb3c990a8c9f0d3db4085429040a7eef9ada5f/cryptography-45.0.7-cp311-abi3-win32.whl", hash = "sha256:bef32a5e327bd8e5af915d3416ffefdbe65ed975b646b3805be81b23580b57b8", size = 2936578, upload-time = "2025-09-01T11:14:17.638Z" }, + { url = "https://files.pythonhosted.org/packages/b3/61/0ab90f421c6194705a99d0fa9f6ee2045d916e4455fdbb095a9c2c9a520f/cryptography-45.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:3808e6b2e5f0b46d981c24d79648e5c25c35e59902ea4391a0dcb3e667bf7443", size = 3405400, upload-time = "2025-09-01T11:14:18.958Z" }, + { url = "https://files.pythonhosted.org/packages/63/e8/c436233ddf19c5f15b25ace33979a9dd2e7aa1a59209a0ee8554179f1cc0/cryptography-45.0.7-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bfb4c801f65dd61cedfc61a83732327fafbac55a47282e6f26f073ca7a41c3b2", size = 7021824, upload-time = "2025-09-01T11:14:20.954Z" }, + { url = "https://files.pythonhosted.org/packages/bc/4c/8f57f2500d0ccd2675c5d0cc462095adf3faa8c52294ba085c036befb901/cryptography-45.0.7-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:81823935e2f8d476707e85a78a405953a03ef7b7b4f55f93f7c2d9680e5e0691", size = 4202233, upload-time = "2025-09-01T11:14:22.454Z" }, + { url = "https://files.pythonhosted.org/packages/eb/ac/59b7790b4ccaed739fc44775ce4645c9b8ce54cbec53edf16c74fd80cb2b/cryptography-45.0.7-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3994c809c17fc570c2af12c9b840d7cea85a9fd3e5c0e0491f4fa3c029216d59", size = 4423075, upload-time = "2025-09-01T11:14:24.287Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/d4f07ea21434bf891faa088a6ac15d6d98093a66e75e30ad08e88aa2b9ba/cryptography-45.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dad43797959a74103cb59c5dac71409f9c27d34c8a05921341fb64ea8ccb1dd4", size = 4204517, upload-time = "2025-09-01T11:14:25.679Z" }, + { url = "https://files.pythonhosted.org/packages/e8/ac/924a723299848b4c741c1059752c7cfe09473b6fd77d2920398fc26bfb53/cryptography-45.0.7-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ce7a453385e4c4693985b4a4a3533e041558851eae061a58a5405363b098fcd3", size = 3882893, upload-time = "2025-09-01T11:14:27.1Z" }, + { url = "https://files.pythonhosted.org/packages/83/dc/4dab2ff0a871cc2d81d3ae6d780991c0192b259c35e4d83fe1de18b20c70/cryptography-45.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b04f85ac3a90c227b6e5890acb0edbaf3140938dbecf07bff618bf3638578cf1", size = 4450132, upload-time = "2025-09-01T11:14:28.58Z" }, + { url = "https://files.pythonhosted.org/packages/12/dd/b2882b65db8fc944585d7fb00d67cf84a9cef4e77d9ba8f69082e911d0de/cryptography-45.0.7-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:48c41a44ef8b8c2e80ca4527ee81daa4c527df3ecbc9423c41a420a9559d0e27", size = 4204086, upload-time = "2025-09-01T11:14:30.572Z" }, + { url = "https://files.pythonhosted.org/packages/5d/fa/1d5745d878048699b8eb87c984d4ccc5da4f5008dfd3ad7a94040caca23a/cryptography-45.0.7-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f3df7b3d0f91b88b2106031fd995802a2e9ae13e02c36c1fc075b43f420f3a17", size = 4449383, upload-time = "2025-09-01T11:14:32.046Z" }, + { url = "https://files.pythonhosted.org/packages/36/8b/fc61f87931bc030598e1876c45b936867bb72777eac693e905ab89832670/cryptography-45.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:dd342f085542f6eb894ca00ef70236ea46070c8a13824c6bde0dfdcd36065b9b", size = 4332186, upload-time = "2025-09-01T11:14:33.95Z" }, + { url = "https://files.pythonhosted.org/packages/0b/11/09700ddad7443ccb11d674efdbe9a832b4455dc1f16566d9bd3834922ce5/cryptography-45.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1993a1bb7e4eccfb922b6cd414f072e08ff5816702a0bdb8941c247a6b1b287c", size = 4561639, upload-time = "2025-09-01T11:14:35.343Z" }, + { url = "https://files.pythonhosted.org/packages/71/ed/8f4c1337e9d3b94d8e50ae0b08ad0304a5709d483bfcadfcc77a23dbcb52/cryptography-45.0.7-cp37-abi3-win32.whl", hash = "sha256:18fcf70f243fe07252dcb1b268a687f2358025ce32f9f88028ca5c364b123ef5", size = 2926552, upload-time = "2025-09-01T11:14:36.929Z" }, + { url = "https://files.pythonhosted.org/packages/bc/ff/026513ecad58dacd45d1d24ebe52b852165a26e287177de1d545325c0c25/cryptography-45.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:7285a89df4900ed3bfaad5679b1e668cb4b38a8de1ccbfc84b05f34512da0a90", size = 3392742, upload-time = "2025-09-01T11:14:38.368Z" }, + { url = "https://files.pythonhosted.org/packages/99/4e/49199a4c82946938a3e05d2e8ad9482484ba48bbc1e809e3d506c686d051/cryptography-45.0.7-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a862753b36620af6fc54209264f92c716367f2f0ff4624952276a6bbd18cbde", size = 3584634, upload-time = "2025-09-01T11:14:50.593Z" }, + { url = "https://files.pythonhosted.org/packages/16/ce/5f6ff59ea9c7779dba51b84871c19962529bdcc12e1a6ea172664916c550/cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:06ce84dc14df0bf6ea84666f958e6080cdb6fe1231be2a51f3fc1267d9f3fb34", size = 4149533, upload-time = "2025-09-01T11:14:52.091Z" }, + { url = "https://files.pythonhosted.org/packages/ce/13/b3cfbd257ac96da4b88b46372e662009b7a16833bfc5da33bb97dd5631ae/cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d0c5c6bac22b177bf8da7435d9d27a6834ee130309749d162b26c3105c0795a9", size = 4385557, upload-time = "2025-09-01T11:14:53.551Z" }, + { url = "https://files.pythonhosted.org/packages/1c/c5/8c59d6b7c7b439ba4fc8d0cab868027fd095f215031bc123c3a070962912/cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:2f641b64acc00811da98df63df7d59fd4706c0df449da71cb7ac39a0732b40ae", size = 4149023, upload-time = "2025-09-01T11:14:55.022Z" }, + { url = "https://files.pythonhosted.org/packages/55/32/05385c86d6ca9ab0b4d5bb442d2e3d85e727939a11f3e163fc776ce5eb40/cryptography-45.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:f5414a788ecc6ee6bc58560e85ca624258a55ca434884445440a810796ea0e0b", size = 4385722, upload-time = "2025-09-01T11:14:57.319Z" }, + { url = "https://files.pythonhosted.org/packages/23/87/7ce86f3fa14bc11a5a48c30d8103c26e09b6465f8d8e9d74cf7a0714f043/cryptography-45.0.7-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:1f3d56f73595376f4244646dd5c5870c14c196949807be39e79e7bd9bac3da63", size = 3332908, upload-time = "2025-09-01T11:14:58.78Z" }, ] [[package]] name = "defusedxml" -version = "0.8.0rc2" +version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/3b/b8849dcc3f96913924137dc4ea041d74aa513a3c5dda83d8366491290c74/defusedxml-0.8.0rc2.tar.gz", hash = "sha256:138c7d540a78775182206c7c97fe65b246a2f40b29471e1a2f1b0da76e7a3942", size = 52575, upload-time = "2023-09-29T08:01:27.517Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/c7/6b4ad89ca6f7732ff97ce5e9caa6fe739600d26c5d53c20d0bf9abb79ec5/defusedxml-0.8.0rc2-py2.py3-none-any.whl", hash = "sha256:1c812964311154c3bf4aaf3bc1443b31ee13530b7f255eaaa062c0553c76103d", size = 25756, upload-time = "2023-09-29T08:01:25.515Z" }, + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, ] [[package]] @@ -1195,11 +1167,11 @@ wheels = [ [[package]] name = "joblib" -version = "1.5.1" +version = "1.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/fe/0f5a938c54105553436dbff7a61dc4fed4b1b2c98852f8833beaf4d5968f/joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444", size = 330475, upload-time = "2025-05-23T12:04:37.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7d/4f/1195bbac8e0c2acc5f740661631d8d750dc38d4a32b23ee5df3cde6f4e0d/joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a", size = 307746, upload-time = "2025-05-23T12:04:35.124Z" }, + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, ] [[package]] @@ -1364,25 +1336,25 @@ wheels = [ [[package]] name = "more-itertools" -version = "10.7.0" +version = "10.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/a0/834b0cebabbfc7e311f30b46c8188790a37f89fc8d756660346fe5abfd09/more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3", size = 127671, upload-time = "2025-04-22T14:17:41.838Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e", size = 65278, upload-time = "2025-04-22T14:17:40.49Z" }, + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, ] [[package]] name = "msal" -version = "1.34.0b1" +version = "1.33.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, { name = "pyjwt", extra = ["crypto"] }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/99/b443d095e0e9d4ec7f46cd60c921f9d24904afb889bf884e8550b8326f02/msal-1.34.0b1.tar.gz", hash = "sha256:86cdbfec14955e803379499d017056c6df4ed40f717fd6addde94bdeb4babd78", size = 154012, upload-time = "2025-08-12T04:57:12.49Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/da/81acbe0c1fd7e9e4ec35f55dadeba9833a847b9a6ba2e2d1e4432da901dd/msal-1.33.0.tar.gz", hash = "sha256:836ad80faa3e25a7d71015c990ce61f704a87328b1e73bcbb0623a18cbf17510", size = 153801, upload-time = "2025-07-22T19:36:33.693Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/a1/04cf04045aff04a699d2cd36eea1b247dbc6fc4dfcb07510e6b0c733fc2c/msal-1.34.0b1-py3-none-any.whl", hash = "sha256:3b6373325e3509d97873e36965a75e9cc9393f1b579d12cc03c0ca0ef6d37eb4", size = 117015, upload-time = "2025-08-12T04:57:11.087Z" }, + { url = "https://files.pythonhosted.org/packages/86/5b/fbc73e91f7727ae1e79b21ed833308e99dc11cc1cd3d4717f579775de5e9/msal-1.33.0-py3-none-any.whl", hash = "sha256:c0cd41cecf8eaed733ee7e3be9e040291eba53b0f262d3ae9c58f38b04244273", size = 116853, upload-time = "2025-07-22T19:36:32.403Z" }, ] [[package]] @@ -1610,7 +1582,7 @@ wheels = [ [[package]] name = "openai" -version = "1.101.0" +version = "1.105.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1622,9 +1594,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/7c/eaf06b62281f5ca4f774c4cff066e6ddfd6a027e0ac791be16acec3a95e3/openai-1.101.0.tar.gz", hash = "sha256:29f56df2236069686e64aca0e13c24a4ec310545afb25ef7da2ab1a18523f22d", size = 518415, upload-time = "2025-08-21T21:11:01.645Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/a9/c8c2dea8066a8f3079f69c242f7d0d75aaad4c4c3431da5b0df22a24e75d/openai-1.105.0.tar.gz", hash = "sha256:a68a47adce0506d34def22dd78a42cbb6cfecae1cf6a5fe37f38776d32bbb514", size = 557265, upload-time = "2025-09-03T14:14:08.586Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/a6/0e39baa335bbd1c66c7e0a41dbbec10c5a15ab95c1344e7f7beb28eee65a/openai-1.101.0-py3-none-any.whl", hash = "sha256:6539a446cce154f8d9fb42757acdfd3ed9357ab0d34fcac11096c461da87133b", size = 810772, upload-time = "2025-08-21T21:10:59.215Z" }, + { url = "https://files.pythonhosted.org/packages/51/01/186845829d3a3609bb5b474067959076244dd62540d3e336797319b13924/openai-1.105.0-py3-none-any.whl", hash = "sha256:3ad7635132b0705769ccae31ca7319f59ec0c7d09e94e5e713ce2d130e5b021f", size = 928203, upload-time = "2025-09-03T14:14:06.842Z" }, ] [[package]] @@ -1834,7 +1806,7 @@ wheels = [ [[package]] name = "opentelemetry-instrumentation-openai" -version = "0.46.1" +version = "0.46.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, @@ -1842,9 +1814,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions-ai" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/0c/defd809a446c37af024d4f394b5e14d0637a3e6d31bcba2f2d9c4debe5fd/opentelemetry_instrumentation_openai-0.46.1.tar.gz", hash = "sha256:cf94ce5ac47f3cb392a2cbb4293f339db7eb35f7a7062a306cbc032b8d609351", size = 25351, upload-time = "2025-08-24T17:03:53.491Z" } +sdist = { url = "https://files.pythonhosted.org/packages/75/42/3ceb2b1a685897c7c3e5e08f3006f5f805a98c23659e1bbfd41a035679b6/opentelemetry_instrumentation_openai-0.46.2.tar.gz", hash = "sha256:5f32380d9018dce3c9af42eaa25a163d20825e66193d57f5a5c4876ec6bf8444", size = 25406, upload-time = "2025-08-29T18:07:57.021Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/b0/55e0eb47b034e16c6035bb4b7c163947500e2d3c3b9550ecd947c9152b27/opentelemetry_instrumentation_openai-0.46.1-py3-none-any.whl", hash = "sha256:f474ffa8500873a1dff9e3f7fbd3aaa93c80bc3775158ab8e2f14ff90dc9d7a3", size = 35212, upload-time = "2025-08-24T17:03:27.573Z" }, + { url = "https://files.pythonhosted.org/packages/da/db/f6637a16f15763f12e727405a8ed0caaaca3f2d786b283fff0cd33d599d5/opentelemetry_instrumentation_openai-0.46.2-py3-none-any.whl", hash = "sha256:0880685a00752c31fdc4c6d9b959342156d62257515e9a8410431fcf7febe2a2", size = 35269, upload-time = "2025-08-29T18:07:30.132Z" }, ] [[package]] @@ -2073,11 +2045,11 @@ wheels = [ [[package]] name = "platformdirs" -version = "4.3.8" +version = "4.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, + { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" }, ] [[package]] @@ -2595,66 +2567,66 @@ wheels = [ [[package]] name = "regex" -version = "2025.7.34" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/de/e13fa6dc61d78b30ba47481f99933a3b49a57779d625c392d8036770a60d/regex-2025.7.34.tar.gz", hash = "sha256:9ead9765217afd04a86822dfcd4ed2747dfe426e887da413b15ff0ac2457e21a", size = 400714, upload-time = "2025-07-31T00:21:16.262Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/85/f497b91577169472f7c1dc262a5ecc65e39e146fc3a52c571e5daaae4b7d/regex-2025.7.34-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:da304313761b8500b8e175eb2040c4394a875837d5635f6256d6fa0377ad32c8", size = 484594, upload-time = "2025-07-31T00:19:13.927Z" }, - { url = "https://files.pythonhosted.org/packages/1c/c5/ad2a5c11ce9e6257fcbfd6cd965d07502f6054aaa19d50a3d7fd991ec5d1/regex-2025.7.34-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:35e43ebf5b18cd751ea81455b19acfdec402e82fe0dc6143edfae4c5c4b3909a", size = 289294, upload-time = "2025-07-31T00:19:15.395Z" }, - { url = "https://files.pythonhosted.org/packages/8e/01/83ffd9641fcf5e018f9b51aa922c3e538ac9439424fda3df540b643ecf4f/regex-2025.7.34-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96bbae4c616726f4661fe7bcad5952e10d25d3c51ddc388189d8864fbc1b3c68", size = 285933, upload-time = "2025-07-31T00:19:16.704Z" }, - { url = "https://files.pythonhosted.org/packages/77/20/5edab2e5766f0259bc1da7381b07ce6eb4401b17b2254d02f492cd8a81a8/regex-2025.7.34-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9feab78a1ffa4f2b1e27b1bcdaad36f48c2fed4870264ce32f52a393db093c78", size = 792335, upload-time = "2025-07-31T00:19:18.561Z" }, - { url = "https://files.pythonhosted.org/packages/30/bd/744d3ed8777dce8487b2606b94925e207e7c5931d5870f47f5b643a4580a/regex-2025.7.34-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f14b36e6d4d07f1a5060f28ef3b3561c5d95eb0651741474ce4c0a4c56ba8719", size = 858605, upload-time = "2025-07-31T00:19:20.204Z" }, - { url = "https://files.pythonhosted.org/packages/99/3d/93754176289718d7578c31d151047e7b8acc7a8c20e7706716f23c49e45e/regex-2025.7.34-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85c3a958ef8b3d5079c763477e1f09e89d13ad22198a37e9d7b26b4b17438b33", size = 905780, upload-time = "2025-07-31T00:19:21.876Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/c689f274a92deffa03999a430505ff2aeace408fd681a90eafa92fdd6930/regex-2025.7.34-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37555e4ae0b93358fa7c2d240a4291d4a4227cc7c607d8f85596cdb08ec0a083", size = 798868, upload-time = "2025-07-31T00:19:23.222Z" }, - { url = "https://files.pythonhosted.org/packages/0d/9e/39673688805d139b33b4a24851a71b9978d61915c4d72b5ffda324d0668a/regex-2025.7.34-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ee38926f31f1aa61b0232a3a11b83461f7807661c062df9eb88769d86e6195c3", size = 781784, upload-time = "2025-07-31T00:19:24.59Z" }, - { url = "https://files.pythonhosted.org/packages/18/bd/4c1cab12cfabe14beaa076523056b8ab0c882a8feaf0a6f48b0a75dab9ed/regex-2025.7.34-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a664291c31cae9c4a30589bd8bc2ebb56ef880c9c6264cb7643633831e606a4d", size = 852837, upload-time = "2025-07-31T00:19:25.911Z" }, - { url = "https://files.pythonhosted.org/packages/cb/21/663d983cbb3bba537fc213a579abbd0f263fb28271c514123f3c547ab917/regex-2025.7.34-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f3e5c1e0925e77ec46ddc736b756a6da50d4df4ee3f69536ffb2373460e2dafd", size = 844240, upload-time = "2025-07-31T00:19:27.688Z" }, - { url = "https://files.pythonhosted.org/packages/8e/2d/9beeeb913bc5d32faa913cf8c47e968da936af61ec20af5d269d0f84a100/regex-2025.7.34-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d428fc7731dcbb4e2ffe43aeb8f90775ad155e7db4347a639768bc6cd2df881a", size = 787139, upload-time = "2025-07-31T00:19:29.475Z" }, - { url = "https://files.pythonhosted.org/packages/eb/f5/9b9384415fdc533551be2ba805dd8c4621873e5df69c958f403bfd3b2b6e/regex-2025.7.34-cp311-cp311-win32.whl", hash = "sha256:e154a7ee7fa18333ad90b20e16ef84daaeac61877c8ef942ec8dfa50dc38b7a1", size = 264019, upload-time = "2025-07-31T00:19:31.129Z" }, - { url = "https://files.pythonhosted.org/packages/18/9d/e069ed94debcf4cc9626d652a48040b079ce34c7e4fb174f16874958d485/regex-2025.7.34-cp311-cp311-win_amd64.whl", hash = "sha256:24257953d5c1d6d3c129ab03414c07fc1a47833c9165d49b954190b2b7f21a1a", size = 276047, upload-time = "2025-07-31T00:19:32.497Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/3bafbe9d1fd1db77355e7fbbbf0d0cfb34501a8b8e334deca14f94c7b315/regex-2025.7.34-cp311-cp311-win_arm64.whl", hash = "sha256:3157aa512b9e606586900888cd469a444f9b898ecb7f8931996cb715f77477f0", size = 268362, upload-time = "2025-07-31T00:19:34.094Z" }, - { url = "https://files.pythonhosted.org/packages/ff/f0/31d62596c75a33f979317658e8d261574785c6cd8672c06741ce2e2e2070/regex-2025.7.34-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7f7211a746aced993bef487de69307a38c5ddd79257d7be83f7b202cb59ddb50", size = 485492, upload-time = "2025-07-31T00:19:35.57Z" }, - { url = "https://files.pythonhosted.org/packages/d8/16/b818d223f1c9758c3434be89aa1a01aae798e0e0df36c1f143d1963dd1ee/regex-2025.7.34-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fb31080f2bd0681484b275461b202b5ad182f52c9ec606052020fe13eb13a72f", size = 290000, upload-time = "2025-07-31T00:19:37.175Z" }, - { url = "https://files.pythonhosted.org/packages/cd/70/69506d53397b4bd6954061bae75677ad34deb7f6ca3ba199660d6f728ff5/regex-2025.7.34-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0200a5150c4cf61e407038f4b4d5cdad13e86345dac29ff9dab3d75d905cf130", size = 286072, upload-time = "2025-07-31T00:19:38.612Z" }, - { url = "https://files.pythonhosted.org/packages/b0/73/536a216d5f66084fb577bb0543b5cb7de3272eb70a157f0c3a542f1c2551/regex-2025.7.34-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:739a74970e736df0773788377969c9fea3876c2fc13d0563f98e5503e5185f46", size = 797341, upload-time = "2025-07-31T00:19:40.119Z" }, - { url = "https://files.pythonhosted.org/packages/26/af/733f8168449e56e8f404bb807ea7189f59507cbea1b67a7bbcd92f8bf844/regex-2025.7.34-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4fef81b2f7ea6a2029161ed6dea9ae13834c28eb5a95b8771828194a026621e4", size = 862556, upload-time = "2025-07-31T00:19:41.556Z" }, - { url = "https://files.pythonhosted.org/packages/19/dd/59c464d58c06c4f7d87de4ab1f590e430821345a40c5d345d449a636d15f/regex-2025.7.34-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea74cf81fe61a7e9d77989050d0089a927ab758c29dac4e8e1b6c06fccf3ebf0", size = 910762, upload-time = "2025-07-31T00:19:43Z" }, - { url = "https://files.pythonhosted.org/packages/37/a8/b05ccf33ceca0815a1e253693b2c86544932ebcc0049c16b0fbdf18b688b/regex-2025.7.34-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e4636a7f3b65a5f340ed9ddf53585c42e3ff37101d383ed321bfe5660481744b", size = 801892, upload-time = "2025-07-31T00:19:44.645Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/b993cb2e634cc22810afd1652dba0cae156c40d4864285ff486c73cd1996/regex-2025.7.34-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cef962d7834437fe8d3da6f9bfc6f93f20f218266dcefec0560ed7765f5fe01", size = 786551, upload-time = "2025-07-31T00:19:46.127Z" }, - { url = "https://files.pythonhosted.org/packages/2d/79/7849d67910a0de4e26834b5bb816e028e35473f3d7ae563552ea04f58ca2/regex-2025.7.34-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:cbe1698e5b80298dbce8df4d8d1182279fbdaf1044e864cbc9d53c20e4a2be77", size = 856457, upload-time = "2025-07-31T00:19:47.562Z" }, - { url = "https://files.pythonhosted.org/packages/91/c6/de516bc082524b27e45cb4f54e28bd800c01efb26d15646a65b87b13a91e/regex-2025.7.34-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:32b9f9bcf0f605eb094b08e8da72e44badabb63dde6b83bd530580b488d1c6da", size = 848902, upload-time = "2025-07-31T00:19:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/7d/22/519ff8ba15f732db099b126f039586bd372da6cd4efb810d5d66a5daeda1/regex-2025.7.34-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:524c868ba527eab4e8744a9287809579f54ae8c62fbf07d62aacd89f6026b282", size = 788038, upload-time = "2025-07-31T00:19:50.794Z" }, - { url = "https://files.pythonhosted.org/packages/3f/7d/aabb467d8f57d8149895d133c88eb809a1a6a0fe262c1d508eb9dfabb6f9/regex-2025.7.34-cp312-cp312-win32.whl", hash = "sha256:d600e58ee6d036081c89696d2bdd55d507498a7180df2e19945c6642fac59588", size = 264417, upload-time = "2025-07-31T00:19:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/3b/39/bd922b55a4fc5ad5c13753274e5b536f5b06ec8eb9747675668491c7ab7a/regex-2025.7.34-cp312-cp312-win_amd64.whl", hash = "sha256:9a9ab52a466a9b4b91564437b36417b76033e8778e5af8f36be835d8cb370d62", size = 275387, upload-time = "2025-07-31T00:19:53.593Z" }, - { url = "https://files.pythonhosted.org/packages/f7/3c/c61d2fdcecb754a40475a3d1ef9a000911d3e3fc75c096acf44b0dfb786a/regex-2025.7.34-cp312-cp312-win_arm64.whl", hash = "sha256:c83aec91af9c6fbf7c743274fd952272403ad9a9db05fe9bfc9df8d12b45f176", size = 268482, upload-time = "2025-07-31T00:19:55.183Z" }, - { url = "https://files.pythonhosted.org/packages/15/16/b709b2119975035169a25aa8e4940ca177b1a2e25e14f8d996d09130368e/regex-2025.7.34-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3c9740a77aeef3f5e3aaab92403946a8d34437db930a0280e7e81ddcada61f5", size = 485334, upload-time = "2025-07-31T00:19:56.58Z" }, - { url = "https://files.pythonhosted.org/packages/94/a6/c09136046be0595f0331bc58a0e5f89c2d324cf734e0b0ec53cf4b12a636/regex-2025.7.34-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:69ed3bc611540f2ea70a4080f853741ec698be556b1df404599f8724690edbcd", size = 289942, upload-time = "2025-07-31T00:19:57.943Z" }, - { url = "https://files.pythonhosted.org/packages/36/91/08fc0fd0f40bdfb0e0df4134ee37cfb16e66a1044ac56d36911fd01c69d2/regex-2025.7.34-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d03c6f9dcd562c56527c42b8530aad93193e0b3254a588be1f2ed378cdfdea1b", size = 285991, upload-time = "2025-07-31T00:19:59.837Z" }, - { url = "https://files.pythonhosted.org/packages/be/2f/99dc8f6f756606f0c214d14c7b6c17270b6bbe26d5c1f05cde9dbb1c551f/regex-2025.7.34-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6164b1d99dee1dfad33f301f174d8139d4368a9fb50bf0a3603b2eaf579963ad", size = 797415, upload-time = "2025-07-31T00:20:01.668Z" }, - { url = "https://files.pythonhosted.org/packages/62/cf/2fcdca1110495458ba4e95c52ce73b361cf1cafd8a53b5c31542cde9a15b/regex-2025.7.34-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1e4f4f62599b8142362f164ce776f19d79bdd21273e86920a7b604a4275b4f59", size = 862487, upload-time = "2025-07-31T00:20:03.142Z" }, - { url = "https://files.pythonhosted.org/packages/90/38/899105dd27fed394e3fae45607c1983e138273ec167e47882fc401f112b9/regex-2025.7.34-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:72a26dcc6a59c057b292f39d41465d8233a10fd69121fa24f8f43ec6294e5415", size = 910717, upload-time = "2025-07-31T00:20:04.727Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f6/4716198dbd0bcc9c45625ac4c81a435d1c4d8ad662e8576dac06bab35b17/regex-2025.7.34-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5273fddf7a3e602695c92716c420c377599ed3c853ea669c1fe26218867002f", size = 801943, upload-time = "2025-07-31T00:20:07.1Z" }, - { url = "https://files.pythonhosted.org/packages/40/5d/cff8896d27e4e3dd11dd72ac78797c7987eb50fe4debc2c0f2f1682eb06d/regex-2025.7.34-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c1844be23cd40135b3a5a4dd298e1e0c0cb36757364dd6cdc6025770363e06c1", size = 786664, upload-time = "2025-07-31T00:20:08.818Z" }, - { url = "https://files.pythonhosted.org/packages/10/29/758bf83cf7b4c34f07ac3423ea03cee3eb3176941641e4ccc05620f6c0b8/regex-2025.7.34-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dde35e2afbbe2272f8abee3b9fe6772d9b5a07d82607b5788e8508974059925c", size = 856457, upload-time = "2025-07-31T00:20:10.328Z" }, - { url = "https://files.pythonhosted.org/packages/d7/30/c19d212b619963c5b460bfed0ea69a092c6a43cba52a973d46c27b3e2975/regex-2025.7.34-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f6e8e7af516a7549412ce57613e859c3be27d55341a894aacaa11703a4c31a", size = 849008, upload-time = "2025-07-31T00:20:11.823Z" }, - { url = "https://files.pythonhosted.org/packages/9e/b8/3c35da3b12c87e3cc00010ef6c3a4ae787cff0bc381aa3d251def219969a/regex-2025.7.34-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:469142fb94a869beb25b5f18ea87646d21def10fbacb0bcb749224f3509476f0", size = 788101, upload-time = "2025-07-31T00:20:13.729Z" }, - { url = "https://files.pythonhosted.org/packages/47/80/2f46677c0b3c2b723b2c358d19f9346e714113865da0f5f736ca1a883bde/regex-2025.7.34-cp313-cp313-win32.whl", hash = "sha256:da7507d083ee33ccea1310447410c27ca11fb9ef18c95899ca57ff60a7e4d8f1", size = 264401, upload-time = "2025-07-31T00:20:15.233Z" }, - { url = "https://files.pythonhosted.org/packages/be/fa/917d64dd074682606a003cba33585c28138c77d848ef72fc77cbb1183849/regex-2025.7.34-cp313-cp313-win_amd64.whl", hash = "sha256:9d644de5520441e5f7e2db63aec2748948cc39ed4d7a87fd5db578ea4043d997", size = 275368, upload-time = "2025-07-31T00:20:16.711Z" }, - { url = "https://files.pythonhosted.org/packages/65/cd/f94383666704170a2154a5df7b16be28f0c27a266bffcd843e58bc84120f/regex-2025.7.34-cp313-cp313-win_arm64.whl", hash = "sha256:7bf1c5503a9f2cbd2f52d7e260acb3131b07b6273c470abb78568174fe6bde3f", size = 268482, upload-time = "2025-07-31T00:20:18.189Z" }, - { url = "https://files.pythonhosted.org/packages/ac/23/6376f3a23cf2f3c00514b1cdd8c990afb4dfbac3cb4a68b633c6b7e2e307/regex-2025.7.34-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:8283afe7042d8270cecf27cca558873168e771183d4d593e3c5fe5f12402212a", size = 485385, upload-time = "2025-07-31T00:20:19.692Z" }, - { url = "https://files.pythonhosted.org/packages/73/5b/6d4d3a0b4d312adbfd6d5694c8dddcf1396708976dd87e4d00af439d962b/regex-2025.7.34-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6c053f9647e3421dd2f5dff8172eb7b4eec129df9d1d2f7133a4386319b47435", size = 289788, upload-time = "2025-07-31T00:20:21.941Z" }, - { url = "https://files.pythonhosted.org/packages/92/71/5862ac9913746e5054d01cb9fb8125b3d0802c0706ef547cae1e7f4428fa/regex-2025.7.34-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a16dd56bbcb7d10e62861c3cd000290ddff28ea142ffb5eb3470f183628011ac", size = 286136, upload-time = "2025-07-31T00:20:26.146Z" }, - { url = "https://files.pythonhosted.org/packages/27/df/5b505dc447eb71278eba10d5ec940769ca89c1af70f0468bfbcb98035dc2/regex-2025.7.34-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69c593ff5a24c0d5c1112b0df9b09eae42b33c014bdca7022d6523b210b69f72", size = 797753, upload-time = "2025-07-31T00:20:27.919Z" }, - { url = "https://files.pythonhosted.org/packages/86/38/3e3dc953d13998fa047e9a2414b556201dbd7147034fbac129392363253b/regex-2025.7.34-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98d0ce170fcde1a03b5df19c5650db22ab58af375aaa6ff07978a85c9f250f0e", size = 863263, upload-time = "2025-07-31T00:20:29.803Z" }, - { url = "https://files.pythonhosted.org/packages/68/e5/3ff66b29dde12f5b874dda2d9dec7245c2051f2528d8c2a797901497f140/regex-2025.7.34-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d72765a4bff8c43711d5b0f5b452991a9947853dfa471972169b3cc0ba1d0751", size = 910103, upload-time = "2025-07-31T00:20:31.313Z" }, - { url = "https://files.pythonhosted.org/packages/9e/fe/14176f2182125977fba3711adea73f472a11f3f9288c1317c59cd16ad5e6/regex-2025.7.34-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4494f8fd95a77eb434039ad8460e64d57baa0434f1395b7da44015bef650d0e4", size = 801709, upload-time = "2025-07-31T00:20:33.323Z" }, - { url = "https://files.pythonhosted.org/packages/5a/0d/80d4e66ed24f1ba876a9e8e31b709f9fd22d5c266bf5f3ab3c1afe683d7d/regex-2025.7.34-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4f42b522259c66e918a0121a12429b2abcf696c6f967fa37bdc7b72e61469f98", size = 786726, upload-time = "2025-07-31T00:20:35.252Z" }, - { url = "https://files.pythonhosted.org/packages/12/75/c3ebb30e04a56c046f5c85179dc173818551037daae2c0c940c7b19152cb/regex-2025.7.34-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:aaef1f056d96a0a5d53ad47d019d5b4c66fe4be2da87016e0d43b7242599ffc7", size = 857306, upload-time = "2025-07-31T00:20:37.12Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b2/a4dc5d8b14f90924f27f0ac4c4c4f5e195b723be98adecc884f6716614b6/regex-2025.7.34-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:656433e5b7dccc9bc0da6312da8eb897b81f5e560321ec413500e5367fcd5d47", size = 848494, upload-time = "2025-07-31T00:20:38.818Z" }, - { url = "https://files.pythonhosted.org/packages/0d/21/9ac6e07a4c5e8646a90b56b61f7e9dac11ae0747c857f91d3d2bc7c241d9/regex-2025.7.34-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e91eb2c62c39705e17b4d42d4b86c4e86c884c0d15d9c5a47d0835f8387add8e", size = 787850, upload-time = "2025-07-31T00:20:40.478Z" }, - { url = "https://files.pythonhosted.org/packages/be/6c/d51204e28e7bc54f9a03bb799b04730d7e54ff2718862b8d4e09e7110a6a/regex-2025.7.34-cp314-cp314-win32.whl", hash = "sha256:f978ddfb6216028c8f1d6b0f7ef779949498b64117fc35a939022f67f810bdcb", size = 269730, upload-time = "2025-07-31T00:20:42.253Z" }, - { url = "https://files.pythonhosted.org/packages/74/52/a7e92d02fa1fdef59d113098cb9f02c5d03289a0e9f9e5d4d6acccd10677/regex-2025.7.34-cp314-cp314-win_amd64.whl", hash = "sha256:4b7dc33b9b48fb37ead12ffc7bdb846ac72f99a80373c4da48f64b373a7abeae", size = 278640, upload-time = "2025-07-31T00:20:44.42Z" }, - { url = "https://files.pythonhosted.org/packages/d1/78/a815529b559b1771080faa90c3ab401730661f99d495ab0071649f139ebd/regex-2025.7.34-cp314-cp314-win_arm64.whl", hash = "sha256:4b8c4d39f451e64809912c82392933d80fe2e4a87eeef8859fcc5380d0173c64", size = 271757, upload-time = "2025-07-31T00:20:46.355Z" }, +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/5a/4c63457fbcaf19d138d72b2e9b39405954f98c0349b31c601bfcb151582c/regex-2025.9.1.tar.gz", hash = "sha256:88ac07b38d20b54d79e704e38aa3bd2c0f8027432164226bdee201a1c0c9c9ff", size = 400852, upload-time = "2025-09-01T22:10:10.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/4d/f741543c0c59f96c6625bc6c11fea1da2e378b7d293ffff6f318edc0ce14/regex-2025.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e5bcf112b09bfd3646e4db6bf2e598534a17d502b0c01ea6550ba4eca780c5e6", size = 484811, upload-time = "2025-09-01T22:08:12.834Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bd/27e73e92635b6fbd51afc26a414a3133243c662949cd1cda677fe7bb09bd/regex-2025.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:67a0295a3c31d675a9ee0238d20238ff10a9a2fdb7a1323c798fc7029578b15c", size = 288977, upload-time = "2025-09-01T22:08:14.499Z" }, + { url = "https://files.pythonhosted.org/packages/eb/7d/7dc0c6efc8bc93cd6e9b947581f5fde8a5dbaa0af7c4ec818c5729fdc807/regex-2025.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea8267fbadc7d4bd7c1301a50e85c2ff0de293ff9452a1a9f8d82c6cafe38179", size = 286606, upload-time = "2025-09-01T22:08:15.881Z" }, + { url = "https://files.pythonhosted.org/packages/d1/01/9b5c6dd394f97c8f2c12f6e8f96879c9ac27292a718903faf2e27a0c09f6/regex-2025.9.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6aeff21de7214d15e928fb5ce757f9495214367ba62875100d4c18d293750cc1", size = 792436, upload-time = "2025-09-01T22:08:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/fc/24/b7430cfc6ee34bbb3db6ff933beb5e7692e5cc81e8f6f4da63d353566fb0/regex-2025.9.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d89f1bbbbbc0885e1c230f7770d5e98f4f00b0ee85688c871d10df8b184a6323", size = 858705, upload-time = "2025-09-01T22:08:19.037Z" }, + { url = "https://files.pythonhosted.org/packages/d6/98/155f914b4ea6ae012663188545c4f5216c11926d09b817127639d618b003/regex-2025.9.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca3affe8ddea498ba9d294ab05f5f2d3b5ad5d515bc0d4a9016dd592a03afe52", size = 905881, upload-time = "2025-09-01T22:08:20.377Z" }, + { url = "https://files.pythonhosted.org/packages/8a/a7/a470e7bc8259c40429afb6d6a517b40c03f2f3e455c44a01abc483a1c512/regex-2025.9.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91892a7a9f0a980e4c2c85dd19bc14de2b219a3a8867c4b5664b9f972dcc0c78", size = 798968, upload-time = "2025-09-01T22:08:22.081Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fa/33f6fec4d41449fea5f62fdf5e46d668a1c046730a7f4ed9f478331a8e3a/regex-2025.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e1cb40406f4ae862710615f9f636c1e030fd6e6abe0e0f65f6a695a2721440c6", size = 781884, upload-time = "2025-09-01T22:08:23.832Z" }, + { url = "https://files.pythonhosted.org/packages/42/de/2b45f36ab20da14eedddf5009d370625bc5942d9953fa7e5037a32d66843/regex-2025.9.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:94f6cff6f7e2149c7e6499a6ecd4695379eeda8ccbccb9726e8149f2fe382e92", size = 852935, upload-time = "2025-09-01T22:08:25.536Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f9/878f4fc92c87e125e27aed0f8ee0d1eced9b541f404b048f66f79914475a/regex-2025.9.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6c0226fb322b82709e78c49cc33484206647f8a39954d7e9de1567f5399becd0", size = 844340, upload-time = "2025-09-01T22:08:27.141Z" }, + { url = "https://files.pythonhosted.org/packages/90/c2/5b6f2bce6ece5f8427c718c085eca0de4bbb4db59f54db77aa6557aef3e9/regex-2025.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a12f59c7c380b4fcf7516e9cbb126f95b7a9518902bcf4a852423ff1dcd03e6a", size = 787238, upload-time = "2025-09-01T22:08:28.75Z" }, + { url = "https://files.pythonhosted.org/packages/47/66/1ef1081c831c5b611f6f55f6302166cfa1bc9574017410ba5595353f846a/regex-2025.9.1-cp311-cp311-win32.whl", hash = "sha256:49865e78d147a7a4f143064488da5d549be6bfc3f2579e5044cac61f5c92edd4", size = 264118, upload-time = "2025-09-01T22:08:30.388Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e0/8adc550d7169df1d6b9be8ff6019cda5291054a0107760c2f30788b6195f/regex-2025.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:d34b901f6f2f02ef60f4ad3855d3a02378c65b094efc4b80388a3aeb700a5de7", size = 276151, upload-time = "2025-09-01T22:08:32.073Z" }, + { url = "https://files.pythonhosted.org/packages/cb/bd/46fef29341396d955066e55384fb93b0be7d64693842bf4a9a398db6e555/regex-2025.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:47d7c2dab7e0b95b95fd580087b6ae196039d62306a592fa4e162e49004b6299", size = 268460, upload-time = "2025-09-01T22:08:33.281Z" }, + { url = "https://files.pythonhosted.org/packages/39/ef/a0372febc5a1d44c1be75f35d7e5aff40c659ecde864d7fa10e138f75e74/regex-2025.9.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:84a25164bd8dcfa9f11c53f561ae9766e506e580b70279d05a7946510bdd6f6a", size = 486317, upload-time = "2025-09-01T22:08:34.529Z" }, + { url = "https://files.pythonhosted.org/packages/b5/25/d64543fb7eb41a1024786d518cc57faf1ce64aa6e9ddba097675a0c2f1d2/regex-2025.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:645e88a73861c64c1af558dd12294fb4e67b5c1eae0096a60d7d8a2143a611c7", size = 289698, upload-time = "2025-09-01T22:08:36.162Z" }, + { url = "https://files.pythonhosted.org/packages/d8/dc/fbf31fc60be317bd9f6f87daa40a8a9669b3b392aa8fe4313df0a39d0722/regex-2025.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10a450cba5cd5409526ee1d4449f42aad38dd83ac6948cbd6d7f71ca7018f7db", size = 287242, upload-time = "2025-09-01T22:08:37.794Z" }, + { url = "https://files.pythonhosted.org/packages/0f/74/f933a607a538f785da5021acf5323961b4620972e2c2f1f39b6af4b71db7/regex-2025.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9dc5991592933a4192c166eeb67b29d9234f9c86344481173d1bc52f73a7104", size = 797441, upload-time = "2025-09-01T22:08:39.108Z" }, + { url = "https://files.pythonhosted.org/packages/89/d0/71fc49b4f20e31e97f199348b8c4d6e613e7b6a54a90eb1b090c2b8496d7/regex-2025.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a32291add816961aab472f4fad344c92871a2ee33c6c219b6598e98c1f0108f2", size = 862654, upload-time = "2025-09-01T22:08:40.586Z" }, + { url = "https://files.pythonhosted.org/packages/59/05/984edce1411a5685ba9abbe10d42cdd9450aab4a022271f9585539788150/regex-2025.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:588c161a68a383478e27442a678e3b197b13c5ba51dbba40c1ccb8c4c7bee9e9", size = 910862, upload-time = "2025-09-01T22:08:42.416Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/5c891bb5fe0691cc1bad336e3a94b9097fbcf9707ec8ddc1dce9f0397289/regex-2025.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47829ffaf652f30d579534da9085fe30c171fa2a6744a93d52ef7195dc38218b", size = 801991, upload-time = "2025-09-01T22:08:44.072Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ae/fd10d6ad179910f7a1b3e0a7fde1ef8bb65e738e8ac4fd6ecff3f52252e4/regex-2025.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e978e5a35b293ea43f140c92a3269b6ab13fe0a2bf8a881f7ac740f5a6ade85", size = 786651, upload-time = "2025-09-01T22:08:46.079Z" }, + { url = "https://files.pythonhosted.org/packages/30/cf/9d686b07bbc5bf94c879cc168db92542d6bc9fb67088d03479fef09ba9d3/regex-2025.9.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf09903e72411f4bf3ac1eddd624ecfd423f14b2e4bf1c8b547b72f248b7bf7", size = 856556, upload-time = "2025-09-01T22:08:48.376Z" }, + { url = "https://files.pythonhosted.org/packages/91/9d/302f8a29bb8a49528abbab2d357a793e2a59b645c54deae0050f8474785b/regex-2025.9.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d016b0f77be63e49613c9e26aaf4a242f196cd3d7a4f15898f5f0ab55c9b24d2", size = 849001, upload-time = "2025-09-01T22:08:50.067Z" }, + { url = "https://files.pythonhosted.org/packages/93/fa/b4c6dbdedc85ef4caec54c817cd5f4418dbfa2453214119f2538082bf666/regex-2025.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:656563e620de6908cd1c9d4f7b9e0777e3341ca7db9d4383bcaa44709c90281e", size = 788138, upload-time = "2025-09-01T22:08:51.933Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1b/91ee17a3cbf87f81e8c110399279d0e57f33405468f6e70809100f2ff7d8/regex-2025.9.1-cp312-cp312-win32.whl", hash = "sha256:df33f4ef07b68f7ab637b1dbd70accbf42ef0021c201660656601e8a9835de45", size = 264524, upload-time = "2025-09-01T22:08:53.75Z" }, + { url = "https://files.pythonhosted.org/packages/92/28/6ba31cce05b0f1ec6b787921903f83bd0acf8efde55219435572af83c350/regex-2025.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:5aba22dfbc60cda7c0853516104724dc904caa2db55f2c3e6e984eb858d3edf3", size = 275489, upload-time = "2025-09-01T22:08:55.037Z" }, + { url = "https://files.pythonhosted.org/packages/bd/ed/ea49f324db00196e9ef7fe00dd13c6164d5173dd0f1bbe495e61bb1fb09d/regex-2025.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:ec1efb4c25e1849c2685fa95da44bfde1b28c62d356f9c8d861d4dad89ed56e9", size = 268589, upload-time = "2025-09-01T22:08:56.369Z" }, + { url = "https://files.pythonhosted.org/packages/98/25/b2959ce90c6138c5142fe5264ee1f9b71a0c502ca4c7959302a749407c79/regex-2025.9.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bc6834727d1b98d710a63e6c823edf6ffbf5792eba35d3fa119531349d4142ef", size = 485932, upload-time = "2025-09-01T22:08:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/49/2e/6507a2a85f3f2be6643438b7bd976e67ad73223692d6988eb1ff444106d3/regex-2025.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c3dc05b6d579875719bccc5f3037b4dc80433d64e94681a0061845bd8863c025", size = 289568, upload-time = "2025-09-01T22:08:59.258Z" }, + { url = "https://files.pythonhosted.org/packages/c7/d8/de4a4b57215d99868f1640e062a7907e185ec7476b4b689e2345487c1ff4/regex-2025.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22213527df4c985ec4a729b055a8306272d41d2f45908d7bacb79be0fa7a75ad", size = 286984, upload-time = "2025-09-01T22:09:00.835Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/e8cb403403a57ed316e80661db0e54d7aa2efcd85cb6156f33cc18746922/regex-2025.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e3f6e3c5a5a1adc3f7ea1b5aec89abfc2f4fbfba55dafb4343cd1d084f715b2", size = 797514, upload-time = "2025-09-01T22:09:02.538Z" }, + { url = "https://files.pythonhosted.org/packages/e4/26/2446f2b9585fed61faaa7e2bbce3aca7dd8df6554c32addee4c4caecf24a/regex-2025.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcb89c02a0d6c2bec9b0bb2d8c78782699afe8434493bfa6b4021cc51503f249", size = 862586, upload-time = "2025-09-01T22:09:04.322Z" }, + { url = "https://files.pythonhosted.org/packages/fd/b8/82ffbe9c0992c31bbe6ae1c4b4e21269a5df2559102b90543c9b56724c3c/regex-2025.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b0e2f95413eb0c651cd1516a670036315b91b71767af83bc8525350d4375ccba", size = 910815, upload-time = "2025-09-01T22:09:05.978Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d8/7303ea38911759c1ee30cc5bc623ee85d3196b733c51fd6703c34290a8d9/regex-2025.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a41dc039e1c97d3c2ed3e26523f748e58c4de3ea7a31f95e1cf9ff973fff5a", size = 802042, upload-time = "2025-09-01T22:09:07.865Z" }, + { url = "https://files.pythonhosted.org/packages/fc/0e/6ad51a55ed4b5af512bb3299a05d33309bda1c1d1e1808fa869a0bed31bc/regex-2025.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f0b4258b161094f66857a26ee938d3fe7b8a5063861e44571215c44fbf0e5df", size = 786764, upload-time = "2025-09-01T22:09:09.362Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d5/394e3ffae6baa5a9217bbd14d96e0e5da47bb069d0dbb8278e2681a2b938/regex-2025.9.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bf70e18ac390e6977ea7e56f921768002cb0fa359c4199606c7219854ae332e0", size = 856557, upload-time = "2025-09-01T22:09:11.129Z" }, + { url = "https://files.pythonhosted.org/packages/cd/80/b288d3910c41194ad081b9fb4b371b76b0bbfdce93e7709fc98df27b37dc/regex-2025.9.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b84036511e1d2bb0a4ff1aec26951caa2dea8772b223c9e8a19ed8885b32dbac", size = 849108, upload-time = "2025-09-01T22:09:12.877Z" }, + { url = "https://files.pythonhosted.org/packages/d1/cd/5ec76bf626d0d5abdc277b7a1734696f5f3d14fbb4a3e2540665bc305d85/regex-2025.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c2e05dcdfe224047f2a59e70408274c325d019aad96227ab959403ba7d58d2d7", size = 788201, upload-time = "2025-09-01T22:09:14.561Z" }, + { url = "https://files.pythonhosted.org/packages/b5/36/674672f3fdead107565a2499f3007788b878188acec6d42bc141c5366c2c/regex-2025.9.1-cp313-cp313-win32.whl", hash = "sha256:3b9a62107a7441b81ca98261808fed30ae36ba06c8b7ee435308806bd53c1ed8", size = 264508, upload-time = "2025-09-01T22:09:16.193Z" }, + { url = "https://files.pythonhosted.org/packages/83/ad/931134539515eb64ce36c24457a98b83c1b2e2d45adf3254b94df3735a76/regex-2025.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:b38afecc10c177eb34cfae68d669d5161880849ba70c05cbfbe409f08cc939d7", size = 275469, upload-time = "2025-09-01T22:09:17.462Z" }, + { url = "https://files.pythonhosted.org/packages/24/8c/96d34e61c0e4e9248836bf86d69cb224fd222f270fa9045b24e218b65604/regex-2025.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:ec329890ad5e7ed9fc292858554d28d58d56bf62cf964faf0aa57964b21155a0", size = 268586, upload-time = "2025-09-01T22:09:18.948Z" }, + { url = "https://files.pythonhosted.org/packages/21/b1/453cbea5323b049181ec6344a803777914074b9726c9c5dc76749966d12d/regex-2025.9.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:72fb7a016467d364546f22b5ae86c45680a4e0de6b2a6f67441d22172ff641f1", size = 486111, upload-time = "2025-09-01T22:09:20.734Z" }, + { url = "https://files.pythonhosted.org/packages/f6/0e/92577f197bd2f7652c5e2857f399936c1876978474ecc5b068c6d8a79c86/regex-2025.9.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c9527fa74eba53f98ad86be2ba003b3ebe97e94b6eb2b916b31b5f055622ef03", size = 289520, upload-time = "2025-09-01T22:09:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/af/c6/b472398116cca7ea5a6c4d5ccd0fc543f7fd2492cb0c48d2852a11972f73/regex-2025.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c905d925d194c83a63f92422af7544ec188301451b292c8b487f0543726107ca", size = 287215, upload-time = "2025-09-01T22:09:23.657Z" }, + { url = "https://files.pythonhosted.org/packages/cf/11/f12ecb0cf9ca792a32bb92f758589a84149017467a544f2f6bfb45c0356d/regex-2025.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74df7c74a63adcad314426b1f4ea6054a5ab25d05b0244f0c07ff9ce640fa597", size = 797855, upload-time = "2025-09-01T22:09:25.197Z" }, + { url = "https://files.pythonhosted.org/packages/46/88/bbb848f719a540fb5997e71310f16f0b33a92c5d4b4d72d4311487fff2a3/regex-2025.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4f6e935e98ea48c7a2e8be44494de337b57a204470e7f9c9c42f912c414cd6f5", size = 863363, upload-time = "2025-09-01T22:09:26.705Z" }, + { url = "https://files.pythonhosted.org/packages/54/a9/2321eb3e2838f575a78d48e03c1e83ea61bd08b74b7ebbdeca8abc50fc25/regex-2025.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4a62d033cd9ebefc7c5e466731a508dfabee827d80b13f455de68a50d3c2543d", size = 910202, upload-time = "2025-09-01T22:09:28.906Z" }, + { url = "https://files.pythonhosted.org/packages/33/07/d1d70835d7d11b7e126181f316f7213c4572ecf5c5c97bdbb969fb1f38a2/regex-2025.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef971ebf2b93bdc88d8337238be4dfb851cc97ed6808eb04870ef67589415171", size = 801808, upload-time = "2025-09-01T22:09:30.733Z" }, + { url = "https://files.pythonhosted.org/packages/13/d1/29e4d1bed514ef2bf3a4ead3cb8bb88ca8af94130239a4e68aa765c35b1c/regex-2025.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d936a1db208bdca0eca1f2bb2c1ba1d8370b226785c1e6db76e32a228ffd0ad5", size = 786824, upload-time = "2025-09-01T22:09:32.61Z" }, + { url = "https://files.pythonhosted.org/packages/33/27/20d8ccb1bee460faaa851e6e7cc4cfe852a42b70caa1dca22721ba19f02f/regex-2025.9.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:7e786d9e4469698fc63815b8de08a89165a0aa851720eb99f5e0ea9d51dd2b6a", size = 857406, upload-time = "2025-09-01T22:09:34.117Z" }, + { url = "https://files.pythonhosted.org/packages/74/fe/60c6132262dc36430d51e0c46c49927d113d3a38c1aba6a26c7744c84cf3/regex-2025.9.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6b81d7dbc5466ad2c57ce3a0ddb717858fe1a29535c8866f8514d785fdb9fc5b", size = 848593, upload-time = "2025-09-01T22:09:35.598Z" }, + { url = "https://files.pythonhosted.org/packages/cc/ae/2d4ff915622fabbef1af28387bf71e7f2f4944a348b8460d061e85e29bf0/regex-2025.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cd4890e184a6feb0ef195338a6ce68906a8903a0f2eb7e0ab727dbc0a3156273", size = 787951, upload-time = "2025-09-01T22:09:37.139Z" }, + { url = "https://files.pythonhosted.org/packages/85/37/dc127703a9e715a284cc2f7dbdd8a9776fd813c85c126eddbcbdd1ca5fec/regex-2025.9.1-cp314-cp314-win32.whl", hash = "sha256:34679a86230e46164c9e0396b56cab13c0505972343880b9e705083cc5b8ec86", size = 269833, upload-time = "2025-09-01T22:09:39.245Z" }, + { url = "https://files.pythonhosted.org/packages/83/bf/4bed4d3d0570e16771defd5f8f15f7ea2311edcbe91077436d6908956c4a/regex-2025.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:a1196e530a6bfa5f4bde029ac5b0295a6ecfaaffbfffede4bbaf4061d9455b70", size = 278742, upload-time = "2025-09-01T22:09:40.651Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3e/7d7ac6fd085023312421e0d69dfabdfb28e116e513fadbe9afe710c01893/regex-2025.9.1-cp314-cp314-win_arm64.whl", hash = "sha256:f46d525934871ea772930e997d577d48c6983e50f206ff7b66d4ac5f8941e993", size = 271860, upload-time = "2025-09-01T22:09:42.413Z" }, ] [[package]] @@ -2699,110 +2671,110 @@ wheels = [ [[package]] name = "rpds-py" -version = "0.27.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/d9/991a0dee12d9fc53ed027e26a26a64b151d77252ac477e22666b9688bc16/rpds_py-0.27.0.tar.gz", hash = "sha256:8b23cf252f180cda89220b378d917180f29d313cd6a07b2431c0d3b776aae86f", size = 27420, upload-time = "2025-08-07T08:26:39.624Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/c1/49d515434c1752e40f5e35b985260cf27af052593378580a2f139a5be6b8/rpds_py-0.27.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:dbc2ab5d10544eb485baa76c63c501303b716a5c405ff2469a1d8ceffaabf622", size = 371577, upload-time = "2025-08-07T08:23:25.379Z" }, - { url = "https://files.pythonhosted.org/packages/e1/6d/bf2715b2fee5087fa13b752b5fd573f1a93e4134c74d275f709e38e54fe7/rpds_py-0.27.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7ec85994f96a58cf7ed288caa344b7fe31fd1d503bdf13d7331ead5f70ab60d5", size = 354959, upload-time = "2025-08-07T08:23:26.767Z" }, - { url = "https://files.pythonhosted.org/packages/a3/5c/e7762808c746dd19733a81373c10da43926f6a6adcf4920a21119697a60a/rpds_py-0.27.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:190d7285cd3bb6d31d37a0534d7359c1ee191eb194c511c301f32a4afa5a1dd4", size = 381485, upload-time = "2025-08-07T08:23:27.869Z" }, - { url = "https://files.pythonhosted.org/packages/40/51/0d308eb0b558309ca0598bcba4243f52c4cd20e15fe991b5bd75824f2e61/rpds_py-0.27.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c10d92fb6d7fd827e44055fcd932ad93dac6a11e832d51534d77b97d1d85400f", size = 396816, upload-time = "2025-08-07T08:23:29.424Z" }, - { url = "https://files.pythonhosted.org/packages/5c/aa/2d585ec911d78f66458b2c91252134ca0c7c70f687a72c87283173dc0c96/rpds_py-0.27.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd2c1d27ebfe6a015cfa2005b7fe8c52d5019f7bbdd801bc6f7499aab9ae739e", size = 514950, upload-time = "2025-08-07T08:23:30.576Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ef/aced551cc1148179557aed84343073adadf252c91265263ee6203458a186/rpds_py-0.27.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4790c9d5dd565ddb3e9f656092f57268951398cef52e364c405ed3112dc7c7c1", size = 402132, upload-time = "2025-08-07T08:23:32.428Z" }, - { url = "https://files.pythonhosted.org/packages/4b/ac/cf644803d8d417653fe2b3604186861d62ea6afaef1b2284045741baef17/rpds_py-0.27.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4300e15e7d03660f04be84a125d1bdd0e6b2f674bc0723bc0fd0122f1a4585dc", size = 383660, upload-time = "2025-08-07T08:23:33.829Z" }, - { url = "https://files.pythonhosted.org/packages/c9/ec/caf47c55ce02b76cbaeeb2d3b36a73da9ca2e14324e3d75cf72b59dcdac5/rpds_py-0.27.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:59195dc244fc183209cf8a93406889cadde47dfd2f0a6b137783aa9c56d67c85", size = 401730, upload-time = "2025-08-07T08:23:34.97Z" }, - { url = "https://files.pythonhosted.org/packages/0b/71/c1f355afdcd5b99ffc253422aa4bdcb04ccf1491dcd1bda3688a0c07fd61/rpds_py-0.27.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fae4a01ef8c4cb2bbe92ef2063149596907dc4a881a8d26743b3f6b304713171", size = 416122, upload-time = "2025-08-07T08:23:36.062Z" }, - { url = "https://files.pythonhosted.org/packages/38/0f/f4b5b1eda724ed0e04d2b26d8911cdc131451a7ee4c4c020a1387e5c6ded/rpds_py-0.27.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e3dc8d4ede2dbae6c0fc2b6c958bf51ce9fd7e9b40c0f5b8835c3fde44f5807d", size = 558771, upload-time = "2025-08-07T08:23:37.478Z" }, - { url = "https://files.pythonhosted.org/packages/93/c0/5f8b834db2289ab48d5cffbecbb75e35410103a77ac0b8da36bf9544ec1c/rpds_py-0.27.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c3782fb753aa825b4ccabc04292e07897e2fd941448eabf666856c5530277626", size = 587876, upload-time = "2025-08-07T08:23:38.662Z" }, - { url = "https://files.pythonhosted.org/packages/d2/dd/1a1df02ab8eb970115cff2ae31a6f73916609b900dc86961dc382b8c2e5e/rpds_py-0.27.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:887ab1f12b0d227e9260558a4a2320024b20102207ada65c43e1ffc4546df72e", size = 554359, upload-time = "2025-08-07T08:23:39.897Z" }, - { url = "https://files.pythonhosted.org/packages/a1/e4/95a014ab0d51ab6e3bebbdb476a42d992d2bbf9c489d24cff9fda998e925/rpds_py-0.27.0-cp311-cp311-win32.whl", hash = "sha256:5d6790ff400254137b81b8053b34417e2c46921e302d655181d55ea46df58cf7", size = 218084, upload-time = "2025-08-07T08:23:41.086Z" }, - { url = "https://files.pythonhosted.org/packages/49/78/f8d5b71ec65a0376b0de31efcbb5528ce17a9b7fdd19c3763303ccfdedec/rpds_py-0.27.0-cp311-cp311-win_amd64.whl", hash = "sha256:e24d8031a2c62f34853756d9208eeafa6b940a1efcbfe36e8f57d99d52bb7261", size = 230085, upload-time = "2025-08-07T08:23:42.143Z" }, - { url = "https://files.pythonhosted.org/packages/e7/d3/84429745184091e06b4cc70f8597408e314c2d2f7f5e13249af9ffab9e3d/rpds_py-0.27.0-cp311-cp311-win_arm64.whl", hash = "sha256:08680820d23df1df0a0260f714d12966bc6c42d02e8055a91d61e03f0c47dda0", size = 222112, upload-time = "2025-08-07T08:23:43.233Z" }, - { url = "https://files.pythonhosted.org/packages/cd/17/e67309ca1ac993fa1888a0d9b2f5ccc1f67196ace32e76c9f8e1dbbbd50c/rpds_py-0.27.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:19c990fdf5acecbf0623e906ae2e09ce1c58947197f9bced6bbd7482662231c4", size = 362611, upload-time = "2025-08-07T08:23:44.773Z" }, - { url = "https://files.pythonhosted.org/packages/93/2e/28c2fb84aa7aa5d75933d1862d0f7de6198ea22dfd9a0cca06e8a4e7509e/rpds_py-0.27.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c27a7054b5224710fcfb1a626ec3ff4f28bcb89b899148c72873b18210e446b", size = 347680, upload-time = "2025-08-07T08:23:46.014Z" }, - { url = "https://files.pythonhosted.org/packages/44/3e/9834b4c8f4f5fe936b479e623832468aa4bd6beb8d014fecaee9eac6cdb1/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09965b314091829b378b60607022048953e25f0b396c2b70e7c4c81bcecf932e", size = 384600, upload-time = "2025-08-07T08:23:48Z" }, - { url = "https://files.pythonhosted.org/packages/19/78/744123c7b38865a965cd9e6f691fde7ef989a00a256fa8bf15b75240d12f/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14f028eb47f59e9169bfdf9f7ceafd29dd64902141840633683d0bad5b04ff34", size = 400697, upload-time = "2025-08-07T08:23:49.407Z" }, - { url = "https://files.pythonhosted.org/packages/32/97/3c3d32fe7daee0a1f1a678b6d4dfb8c4dcf88197fa2441f9da7cb54a8466/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6168af0be75bba990a39f9431cdfae5f0ad501f4af32ae62e8856307200517b8", size = 517781, upload-time = "2025-08-07T08:23:50.557Z" }, - { url = "https://files.pythonhosted.org/packages/b2/be/28f0e3e733680aa13ecec1212fc0f585928a206292f14f89c0b8a684cad1/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab47fe727c13c09d0e6f508e3a49e545008e23bf762a245b020391b621f5b726", size = 406449, upload-time = "2025-08-07T08:23:51.732Z" }, - { url = "https://files.pythonhosted.org/packages/95/ae/5d15c83e337c082d0367053baeb40bfba683f42459f6ebff63a2fd7e5518/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa01b3d5e3b7d97efab65bd3d88f164e289ec323a8c033c5c38e53ee25c007e", size = 386150, upload-time = "2025-08-07T08:23:52.822Z" }, - { url = "https://files.pythonhosted.org/packages/bf/65/944e95f95d5931112829e040912b25a77b2e7ed913ea5fe5746aa5c1ce75/rpds_py-0.27.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:6c135708e987f46053e0a1246a206f53717f9fadfba27174a9769ad4befba5c3", size = 406100, upload-time = "2025-08-07T08:23:54.339Z" }, - { url = "https://files.pythonhosted.org/packages/21/a4/1664b83fae02894533cd11dc0b9f91d673797c2185b7be0f7496107ed6c5/rpds_py-0.27.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc327f4497b7087d06204235199daf208fd01c82d80465dc5efa4ec9df1c5b4e", size = 421345, upload-time = "2025-08-07T08:23:55.832Z" }, - { url = "https://files.pythonhosted.org/packages/7c/26/b7303941c2b0823bfb34c71378249f8beedce57301f400acb04bb345d025/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e57906e38583a2cba67046a09c2637e23297618dc1f3caddbc493f2be97c93f", size = 561891, upload-time = "2025-08-07T08:23:56.951Z" }, - { url = "https://files.pythonhosted.org/packages/9b/c8/48623d64d4a5a028fa99576c768a6159db49ab907230edddc0b8468b998b/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f4f69d7a4300fbf91efb1fb4916421bd57804c01ab938ab50ac9c4aa2212f03", size = 591756, upload-time = "2025-08-07T08:23:58.146Z" }, - { url = "https://files.pythonhosted.org/packages/b3/51/18f62617e8e61cc66334c9fb44b1ad7baae3438662098efbc55fb3fda453/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b4c4fbbcff474e1e5f38be1bf04511c03d492d42eec0babda5d03af3b5589374", size = 557088, upload-time = "2025-08-07T08:23:59.6Z" }, - { url = "https://files.pythonhosted.org/packages/bd/4c/e84c3a276e2496a93d245516be6b49e20499aa8ca1c94d59fada0d79addc/rpds_py-0.27.0-cp312-cp312-win32.whl", hash = "sha256:27bac29bbbf39601b2aab474daf99dbc8e7176ca3389237a23944b17f8913d97", size = 221926, upload-time = "2025-08-07T08:24:00.695Z" }, - { url = "https://files.pythonhosted.org/packages/83/89/9d0fbcef64340db0605eb0a0044f258076f3ae0a3b108983b2c614d96212/rpds_py-0.27.0-cp312-cp312-win_amd64.whl", hash = "sha256:8a06aa1197ec0281eb1d7daf6073e199eb832fe591ffa329b88bae28f25f5fe5", size = 233235, upload-time = "2025-08-07T08:24:01.846Z" }, - { url = "https://files.pythonhosted.org/packages/c9/b0/e177aa9f39cbab060f96de4a09df77d494f0279604dc2f509263e21b05f9/rpds_py-0.27.0-cp312-cp312-win_arm64.whl", hash = "sha256:e14aab02258cb776a108107bd15f5b5e4a1bbaa61ef33b36693dfab6f89d54f9", size = 223315, upload-time = "2025-08-07T08:24:03.337Z" }, - { url = "https://files.pythonhosted.org/packages/81/d2/dfdfd42565a923b9e5a29f93501664f5b984a802967d48d49200ad71be36/rpds_py-0.27.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:443d239d02d9ae55b74015234f2cd8eb09e59fbba30bf60baeb3123ad4c6d5ff", size = 362133, upload-time = "2025-08-07T08:24:04.508Z" }, - { url = "https://files.pythonhosted.org/packages/ac/4a/0a2e2460c4b66021d349ce9f6331df1d6c75d7eea90df9785d333a49df04/rpds_py-0.27.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8a7acf04fda1f30f1007f3cc96d29d8cf0a53e626e4e1655fdf4eabc082d367", size = 347128, upload-time = "2025-08-07T08:24:05.695Z" }, - { url = "https://files.pythonhosted.org/packages/35/8d/7d1e4390dfe09d4213b3175a3f5a817514355cb3524593380733204f20b9/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d0f92b78cfc3b74a42239fdd8c1266f4715b573204c234d2f9fc3fc7a24f185", size = 384027, upload-time = "2025-08-07T08:24:06.841Z" }, - { url = "https://files.pythonhosted.org/packages/c1/65/78499d1a62172891c8cd45de737b2a4b84a414b6ad8315ab3ac4945a5b61/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ce4ed8e0c7dbc5b19352b9c2c6131dd23b95fa8698b5cdd076307a33626b72dc", size = 399973, upload-time = "2025-08-07T08:24:08.143Z" }, - { url = "https://files.pythonhosted.org/packages/10/a1/1c67c1d8cc889107b19570bb01f75cf49852068e95e6aee80d22915406fc/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fde355b02934cc6b07200cc3b27ab0c15870a757d1a72fd401aa92e2ea3c6bfe", size = 515295, upload-time = "2025-08-07T08:24:09.711Z" }, - { url = "https://files.pythonhosted.org/packages/df/27/700ec88e748436b6c7c4a2262d66e80f8c21ab585d5e98c45e02f13f21c0/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13bbc4846ae4c993f07c93feb21a24d8ec637573d567a924b1001e81c8ae80f9", size = 406737, upload-time = "2025-08-07T08:24:11.182Z" }, - { url = "https://files.pythonhosted.org/packages/33/cc/6b0ee8f0ba3f2df2daac1beda17fde5cf10897a7d466f252bd184ef20162/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0744661afbc4099fef7f4e604e7f1ea1be1dd7284f357924af12a705cc7d5c", size = 385898, upload-time = "2025-08-07T08:24:12.798Z" }, - { url = "https://files.pythonhosted.org/packages/e8/7e/c927b37d7d33c0a0ebf249cc268dc2fcec52864c1b6309ecb960497f2285/rpds_py-0.27.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:069e0384a54f427bd65d7fda83b68a90606a3835901aaff42185fcd94f5a9295", size = 405785, upload-time = "2025-08-07T08:24:14.906Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/8ed50746d909dcf402af3fa58b83d5a590ed43e07251d6b08fad1a535ba6/rpds_py-0.27.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4bc262ace5a1a7dc3e2eac2fa97b8257ae795389f688b5adf22c5db1e2431c43", size = 419760, upload-time = "2025-08-07T08:24:16.129Z" }, - { url = "https://files.pythonhosted.org/packages/d3/60/2b2071aee781cb3bd49f94d5d35686990b925e9b9f3e3d149235a6f5d5c1/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fe6e18e5c8581f0361b35ae575043c7029d0a92cb3429e6e596c2cdde251432", size = 561201, upload-time = "2025-08-07T08:24:17.645Z" }, - { url = "https://files.pythonhosted.org/packages/98/1f/27b67304272521aaea02be293fecedce13fa351a4e41cdb9290576fc6d81/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d93ebdb82363d2e7bec64eecdc3632b59e84bd270d74fe5be1659f7787052f9b", size = 591021, upload-time = "2025-08-07T08:24:18.999Z" }, - { url = "https://files.pythonhosted.org/packages/db/9b/a2fadf823164dd085b1f894be6443b0762a54a7af6f36e98e8fcda69ee50/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0954e3a92e1d62e83a54ea7b3fdc9efa5d61acef8488a8a3d31fdafbfb00460d", size = 556368, upload-time = "2025-08-07T08:24:20.54Z" }, - { url = "https://files.pythonhosted.org/packages/24/f3/6d135d46a129cda2e3e6d4c5e91e2cc26ea0428c6cf152763f3f10b6dd05/rpds_py-0.27.0-cp313-cp313-win32.whl", hash = "sha256:2cff9bdd6c7b906cc562a505c04a57d92e82d37200027e8d362518df427f96cd", size = 221236, upload-time = "2025-08-07T08:24:22.144Z" }, - { url = "https://files.pythonhosted.org/packages/c5/44/65d7494f5448ecc755b545d78b188440f81da98b50ea0447ab5ebfdf9bd6/rpds_py-0.27.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc79d192fb76fc0c84f2c58672c17bbbc383fd26c3cdc29daae16ce3d927e8b2", size = 232634, upload-time = "2025-08-07T08:24:23.642Z" }, - { url = "https://files.pythonhosted.org/packages/70/d9/23852410fadab2abb611733933401de42a1964ce6600a3badae35fbd573e/rpds_py-0.27.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b3a5c8089eed498a3af23ce87a80805ff98f6ef8f7bdb70bd1b7dae5105f6ac", size = 222783, upload-time = "2025-08-07T08:24:25.098Z" }, - { url = "https://files.pythonhosted.org/packages/15/75/03447917f78512b34463f4ef11066516067099a0c466545655503bed0c77/rpds_py-0.27.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:90fb790138c1a89a2e58c9282fe1089638401f2f3b8dddd758499041bc6e0774", size = 359154, upload-time = "2025-08-07T08:24:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/6b/fc/4dac4fa756451f2122ddaf136e2c6aeb758dc6fdbe9ccc4bc95c98451d50/rpds_py-0.27.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:010c4843a3b92b54373e3d2291a7447d6c3fc29f591772cc2ea0e9f5c1da434b", size = 343909, upload-time = "2025-08-07T08:24:27.405Z" }, - { url = "https://files.pythonhosted.org/packages/7b/81/723c1ed8e6f57ed9d8c0c07578747a2d3d554aaefc1ab89f4e42cfeefa07/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9ce7a9e967afc0a2af7caa0d15a3e9c1054815f73d6a8cb9225b61921b419bd", size = 379340, upload-time = "2025-08-07T08:24:28.714Z" }, - { url = "https://files.pythonhosted.org/packages/98/16/7e3740413de71818ce1997df82ba5f94bae9fff90c0a578c0e24658e6201/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa0bf113d15e8abdfee92aa4db86761b709a09954083afcb5bf0f952d6065fdb", size = 391655, upload-time = "2025-08-07T08:24:30.223Z" }, - { url = "https://files.pythonhosted.org/packages/e0/63/2a9f510e124d80660f60ecce07953f3f2d5f0b96192c1365443859b9c87f/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb91d252b35004a84670dfeafadb042528b19842a0080d8b53e5ec1128e8f433", size = 513017, upload-time = "2025-08-07T08:24:31.446Z" }, - { url = "https://files.pythonhosted.org/packages/2c/4e/cf6ff311d09776c53ea1b4f2e6700b9d43bb4e99551006817ade4bbd6f78/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db8a6313dbac934193fc17fe7610f70cd8181c542a91382531bef5ed785e5615", size = 402058, upload-time = "2025-08-07T08:24:32.613Z" }, - { url = "https://files.pythonhosted.org/packages/88/11/5e36096d474cb10f2a2d68b22af60a3bc4164fd8db15078769a568d9d3ac/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce96ab0bdfcef1b8c371ada2100767ace6804ea35aacce0aef3aeb4f3f499ca8", size = 383474, upload-time = "2025-08-07T08:24:33.767Z" }, - { url = "https://files.pythonhosted.org/packages/db/a2/3dff02805b06058760b5eaa6d8cb8db3eb3e46c9e452453ad5fc5b5ad9fe/rpds_py-0.27.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:7451ede3560086abe1aa27dcdcf55cd15c96b56f543fb12e5826eee6f721f858", size = 400067, upload-time = "2025-08-07T08:24:35.021Z" }, - { url = "https://files.pythonhosted.org/packages/67/87/eed7369b0b265518e21ea836456a4ed4a6744c8c12422ce05bce760bb3cf/rpds_py-0.27.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:32196b5a99821476537b3f7732432d64d93a58d680a52c5e12a190ee0135d8b5", size = 412085, upload-time = "2025-08-07T08:24:36.267Z" }, - { url = "https://files.pythonhosted.org/packages/8b/48/f50b2ab2fbb422fbb389fe296e70b7a6b5ea31b263ada5c61377e710a924/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a029be818059870664157194e46ce0e995082ac49926f1423c1f058534d2aaa9", size = 555928, upload-time = "2025-08-07T08:24:37.573Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/b18eb51045d06887666c3560cd4bbb6819127b43d758f5adb82b5f56f7d1/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3841f66c1ffdc6cebce8aed64e36db71466f1dc23c0d9a5592e2a782a3042c79", size = 585527, upload-time = "2025-08-07T08:24:39.391Z" }, - { url = "https://files.pythonhosted.org/packages/be/03/a3dd6470fc76499959b00ae56295b76b4bdf7c6ffc60d62006b1217567e1/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:42894616da0fc0dcb2ec08a77896c3f56e9cb2f4b66acd76fc8992c3557ceb1c", size = 554211, upload-time = "2025-08-07T08:24:40.6Z" }, - { url = "https://files.pythonhosted.org/packages/bf/d1/ee5fd1be395a07423ac4ca0bcc05280bf95db2b155d03adefeb47d5ebf7e/rpds_py-0.27.0-cp313-cp313t-win32.whl", hash = "sha256:b1fef1f13c842a39a03409e30ca0bf87b39a1e2a305a9924deadb75a43105d23", size = 216624, upload-time = "2025-08-07T08:24:42.204Z" }, - { url = "https://files.pythonhosted.org/packages/1c/94/4814c4c858833bf46706f87349c37ca45e154da7dbbec9ff09f1abeb08cc/rpds_py-0.27.0-cp313-cp313t-win_amd64.whl", hash = "sha256:183f5e221ba3e283cd36fdfbe311d95cd87699a083330b4f792543987167eff1", size = 230007, upload-time = "2025-08-07T08:24:43.329Z" }, - { url = "https://files.pythonhosted.org/packages/0e/a5/8fffe1c7dc7c055aa02df310f9fb71cfc693a4d5ccc5de2d3456ea5fb022/rpds_py-0.27.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:f3cd110e02c5bf17d8fb562f6c9df5c20e73029d587cf8602a2da6c5ef1e32cb", size = 362595, upload-time = "2025-08-07T08:24:44.478Z" }, - { url = "https://files.pythonhosted.org/packages/bc/c7/4e4253fd2d4bb0edbc0b0b10d9f280612ca4f0f990e3c04c599000fe7d71/rpds_py-0.27.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8d0e09cf4863c74106b5265c2c310f36146e2b445ff7b3018a56799f28f39f6f", size = 347252, upload-time = "2025-08-07T08:24:45.678Z" }, - { url = "https://files.pythonhosted.org/packages/f3/c8/3d1a954d30f0174dd6baf18b57c215da03cf7846a9d6e0143304e784cddc/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f689ab822f9b5eb6dfc69893b4b9366db1d2420f7db1f6a2adf2a9ca15ad64", size = 384886, upload-time = "2025-08-07T08:24:46.86Z" }, - { url = "https://files.pythonhosted.org/packages/e0/52/3c5835f2df389832b28f9276dd5395b5a965cea34226e7c88c8fbec2093c/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e36c80c49853b3ffda7aa1831bf175c13356b210c73128c861f3aa93c3cc4015", size = 399716, upload-time = "2025-08-07T08:24:48.174Z" }, - { url = "https://files.pythonhosted.org/packages/40/73/176e46992461a1749686a2a441e24df51ff86b99c2d34bf39f2a5273b987/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6de6a7f622860af0146cb9ee148682ff4d0cea0b8fd3ad51ce4d40efb2f061d0", size = 517030, upload-time = "2025-08-07T08:24:49.52Z" }, - { url = "https://files.pythonhosted.org/packages/79/2a/7266c75840e8c6e70effeb0d38922a45720904f2cd695e68a0150e5407e2/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4045e2fc4b37ec4b48e8907a5819bdd3380708c139d7cc358f03a3653abedb89", size = 408448, upload-time = "2025-08-07T08:24:50.727Z" }, - { url = "https://files.pythonhosted.org/packages/e6/5f/a7efc572b8e235093dc6cf39f4dbc8a7f08e65fdbcec7ff4daeb3585eef1/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da162b718b12c4219eeeeb68a5b7552fbc7aadedf2efee440f88b9c0e54b45d", size = 387320, upload-time = "2025-08-07T08:24:52.004Z" }, - { url = "https://files.pythonhosted.org/packages/a2/eb/9ff6bc92efe57cf5a2cb74dee20453ba444b6fdc85275d8c99e0d27239d1/rpds_py-0.27.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:0665be515767dc727ffa5f74bd2ef60b0ff85dad6bb8f50d91eaa6b5fb226f51", size = 407414, upload-time = "2025-08-07T08:24:53.664Z" }, - { url = "https://files.pythonhosted.org/packages/fb/bd/3b9b19b00d5c6e1bd0f418c229ab0f8d3b110ddf7ec5d9d689ef783d0268/rpds_py-0.27.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:203f581accef67300a942e49a37d74c12ceeef4514874c7cede21b012613ca2c", size = 420766, upload-time = "2025-08-07T08:24:55.917Z" }, - { url = "https://files.pythonhosted.org/packages/17/6b/521a7b1079ce16258c70805166e3ac6ec4ee2139d023fe07954dc9b2d568/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7873b65686a6471c0037139aa000d23fe94628e0daaa27b6e40607c90e3f5ec4", size = 562409, upload-time = "2025-08-07T08:24:57.17Z" }, - { url = "https://files.pythonhosted.org/packages/8b/bf/65db5bfb14ccc55e39de8419a659d05a2a9cd232f0a699a516bb0991da7b/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:249ab91ceaa6b41abc5f19513cb95b45c6f956f6b89f1fe3d99c81255a849f9e", size = 590793, upload-time = "2025-08-07T08:24:58.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/b8/82d368b378325191ba7aae8f40f009b78057b598d4394d1f2cdabaf67b3f/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2f184336bc1d6abfaaa1262ed42739c3789b1e3a65a29916a615307d22ffd2e", size = 558178, upload-time = "2025-08-07T08:24:59.756Z" }, - { url = "https://files.pythonhosted.org/packages/f6/ff/f270bddbfbc3812500f8131b1ebbd97afd014cd554b604a3f73f03133a36/rpds_py-0.27.0-cp314-cp314-win32.whl", hash = "sha256:d3c622c39f04d5751408f5b801ecb527e6e0a471b367f420a877f7a660d583f6", size = 222355, upload-time = "2025-08-07T08:25:01.027Z" }, - { url = "https://files.pythonhosted.org/packages/bf/20/fdab055b1460c02ed356a0e0b0a78c1dd32dc64e82a544f7b31c9ac643dc/rpds_py-0.27.0-cp314-cp314-win_amd64.whl", hash = "sha256:cf824aceaeffff029ccfba0da637d432ca71ab21f13e7f6f5179cd88ebc77a8a", size = 234007, upload-time = "2025-08-07T08:25:02.268Z" }, - { url = "https://files.pythonhosted.org/packages/4d/a8/694c060005421797a3be4943dab8347c76c2b429a9bef68fb2c87c9e70c7/rpds_py-0.27.0-cp314-cp314-win_arm64.whl", hash = "sha256:86aca1616922b40d8ac1b3073a1ead4255a2f13405e5700c01f7c8d29a03972d", size = 223527, upload-time = "2025-08-07T08:25:03.45Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f9/77f4c90f79d2c5ca8ce6ec6a76cb4734ee247de6b3a4f337e289e1f00372/rpds_py-0.27.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:341d8acb6724c0c17bdf714319c393bb27f6d23d39bc74f94221b3e59fc31828", size = 359469, upload-time = "2025-08-07T08:25:04.648Z" }, - { url = "https://files.pythonhosted.org/packages/c0/22/b97878d2f1284286fef4172069e84b0b42b546ea7d053e5fb7adb9ac6494/rpds_py-0.27.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6b96b0b784fe5fd03beffff2b1533dc0d85e92bab8d1b2c24ef3a5dc8fac5669", size = 343960, upload-time = "2025-08-07T08:25:05.863Z" }, - { url = "https://files.pythonhosted.org/packages/b1/b0/dfd55b5bb480eda0578ae94ef256d3061d20b19a0f5e18c482f03e65464f/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c431bfb91478d7cbe368d0a699978050d3b112d7f1d440a41e90faa325557fd", size = 380201, upload-time = "2025-08-07T08:25:07.513Z" }, - { url = "https://files.pythonhosted.org/packages/28/22/e1fa64e50d58ad2b2053077e3ec81a979147c43428de9e6de68ddf6aff4e/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e222a44ae9f507d0f2678ee3dd0c45ec1e930f6875d99b8459631c24058aec", size = 392111, upload-time = "2025-08-07T08:25:09.149Z" }, - { url = "https://files.pythonhosted.org/packages/49/f9/43ab7a43e97aedf6cea6af70fdcbe18abbbc41d4ae6cdec1bfc23bbad403/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:184f0d7b342967f6cda94a07d0e1fae177d11d0b8f17d73e06e36ac02889f303", size = 515863, upload-time = "2025-08-07T08:25:10.431Z" }, - { url = "https://files.pythonhosted.org/packages/38/9b/9bd59dcc636cd04d86a2d20ad967770bf348f5eb5922a8f29b547c074243/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a00c91104c173c9043bc46f7b30ee5e6d2f6b1149f11f545580f5d6fdff42c0b", size = 402398, upload-time = "2025-08-07T08:25:11.819Z" }, - { url = "https://files.pythonhosted.org/packages/71/bf/f099328c6c85667aba6b66fa5c35a8882db06dcd462ea214be72813a0dd2/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a37dd208f0d658e0487522078b1ed68cd6bce20ef4b5a915d2809b9094b410", size = 384665, upload-time = "2025-08-07T08:25:13.194Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c5/9c1f03121ece6634818490bd3c8be2c82a70928a19de03467fb25a3ae2a8/rpds_py-0.27.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:92f3b3ec3e6008a1fe00b7c0946a170f161ac00645cde35e3c9a68c2475e8156", size = 400405, upload-time = "2025-08-07T08:25:14.417Z" }, - { url = "https://files.pythonhosted.org/packages/b5/b8/e25d54af3e63ac94f0c16d8fe143779fe71ff209445a0c00d0f6984b6b2c/rpds_py-0.27.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1b3db5fae5cbce2131b7420a3f83553d4d89514c03d67804ced36161fe8b6b2", size = 413179, upload-time = "2025-08-07T08:25:15.664Z" }, - { url = "https://files.pythonhosted.org/packages/f9/d1/406b3316433fe49c3021546293a04bc33f1478e3ec7950215a7fce1a1208/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5355527adaa713ab693cbce7c1e0ec71682f599f61b128cf19d07e5c13c9b1f1", size = 556895, upload-time = "2025-08-07T08:25:17.061Z" }, - { url = "https://files.pythonhosted.org/packages/5f/bc/3697c0c21fcb9a54d46ae3b735eb2365eea0c2be076b8f770f98e07998de/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fcc01c57ce6e70b728af02b2401c5bc853a9e14eb07deda30624374f0aebfe42", size = 585464, upload-time = "2025-08-07T08:25:18.406Z" }, - { url = "https://files.pythonhosted.org/packages/63/09/ee1bb5536f99f42c839b177d552f6114aa3142d82f49cef49261ed28dbe0/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3001013dae10f806380ba739d40dee11db1ecb91684febb8406a87c2ded23dae", size = 555090, upload-time = "2025-08-07T08:25:20.461Z" }, - { url = "https://files.pythonhosted.org/packages/7d/2c/363eada9e89f7059199d3724135a86c47082cbf72790d6ba2f336d146ddb/rpds_py-0.27.0-cp314-cp314t-win32.whl", hash = "sha256:0f401c369186a5743694dd9fc08cba66cf70908757552e1f714bfc5219c655b5", size = 218001, upload-time = "2025-08-07T08:25:21.761Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3f/d6c216ed5199c9ef79e2a33955601f454ed1e7420a93b89670133bca5ace/rpds_py-0.27.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8a1dca5507fa1337f75dcd5070218b20bc68cf8844271c923c1b79dfcbc20391", size = 230993, upload-time = "2025-08-07T08:25:23.34Z" }, - { url = "https://files.pythonhosted.org/packages/59/64/72ab5b911fdcc48058359b0e786e5363e3fde885156116026f1a2ba9a5b5/rpds_py-0.27.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e6491658dd2569f05860bad645569145c8626ac231877b0fb2d5f9bcb7054089", size = 371658, upload-time = "2025-08-07T08:26:02.369Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4b/90ff04b4da055db53d8fea57640d8d5d55456343a1ec9a866c0ecfe10fd1/rpds_py-0.27.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:bec77545d188f8bdd29d42bccb9191682a46fb2e655e3d1fb446d47c55ac3b8d", size = 355529, upload-time = "2025-08-07T08:26:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/a4/be/527491fb1afcd86fc5ce5812eb37bc70428ee017d77fee20de18155c3937/rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a4aebf8ca02bbb90a9b3e7a463bbf3bee02ab1c446840ca07b1695a68ce424", size = 382822, upload-time = "2025-08-07T08:26:05.52Z" }, - { url = "https://files.pythonhosted.org/packages/e0/a5/dcdb8725ce11e6d0913e6fcf782a13f4b8a517e8acc70946031830b98441/rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:44524b96481a4c9b8e6c46d6afe43fa1fb485c261e359fbe32b63ff60e3884d8", size = 397233, upload-time = "2025-08-07T08:26:07.179Z" }, - { url = "https://files.pythonhosted.org/packages/33/f9/0947920d1927e9f144660590cc38cadb0795d78fe0d9aae0ef71c1513b7c/rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45d04a73c54b6a5fd2bab91a4b5bc8b426949586e61340e212a8484919183859", size = 514892, upload-time = "2025-08-07T08:26:08.622Z" }, - { url = "https://files.pythonhosted.org/packages/1d/ed/d1343398c1417c68f8daa1afce56ef6ce5cc587daaf98e29347b00a80ff2/rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:343cf24de9ed6c728abefc5d5c851d5de06497caa7ac37e5e65dd572921ed1b5", size = 402733, upload-time = "2025-08-07T08:26:10.433Z" }, - { url = "https://files.pythonhosted.org/packages/1d/0b/646f55442cd14014fb64d143428f25667a100f82092c90087b9ea7101c74/rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aed8118ae20515974650d08eb724150dc2e20c2814bcc307089569995e88a14", size = 384447, upload-time = "2025-08-07T08:26:11.847Z" }, - { url = "https://files.pythonhosted.org/packages/4b/15/0596ef7529828e33a6c81ecf5013d1dd33a511a3e0be0561f83079cda227/rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:af9d4fd79ee1cc8e7caf693ee02737daabfc0fcf2773ca0a4735b356c8ad6f7c", size = 402502, upload-time = "2025-08-07T08:26:13.537Z" }, - { url = "https://files.pythonhosted.org/packages/c3/8d/986af3c42f8454a6cafff8729d99fb178ae9b08a9816325ac7a8fa57c0c0/rpds_py-0.27.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f0396e894bd1e66c74ecbc08b4f6a03dc331140942c4b1d345dd131b68574a60", size = 416651, upload-time = "2025-08-07T08:26:14.923Z" }, - { url = "https://files.pythonhosted.org/packages/e9/9a/b4ec3629b7b447e896eec574469159b5b60b7781d3711c914748bf32de05/rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:59714ab0a5af25d723d8e9816638faf7f4254234decb7d212715c1aa71eee7be", size = 559460, upload-time = "2025-08-07T08:26:16.295Z" }, - { url = "https://files.pythonhosted.org/packages/61/63/d1e127b40c3e4733b3a6f26ae7a063cdf2bc1caa5272c89075425c7d397a/rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:88051c3b7d5325409f433c5a40328fcb0685fc04e5db49ff936e910901d10114", size = 588072, upload-time = "2025-08-07T08:26:17.776Z" }, - { url = "https://files.pythonhosted.org/packages/04/7e/8ffc71a8f6833d9c9fb999f5b0ee736b8b159fd66968e05c7afc2dbcd57e/rpds_py-0.27.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:181bc29e59e5e5e6e9d63b143ff4d5191224d355e246b5a48c88ce6b35c4e466", size = 555083, upload-time = "2025-08-07T08:26:19.301Z" }, +version = "0.27.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/dd/2c0cbe774744272b0ae725f44032c77bdcab6e8bcf544bffa3b6e70c8dba/rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8", size = 27479, upload-time = "2025-08-27T12:16:36.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/c1/7907329fbef97cbd49db6f7303893bd1dd5a4a3eae415839ffdfb0762cae/rpds_py-0.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:be898f271f851f68b318872ce6ebebbc62f303b654e43bf72683dbdc25b7c881", size = 371063, upload-time = "2025-08-27T12:12:47.856Z" }, + { url = "https://files.pythonhosted.org/packages/11/94/2aab4bc86228bcf7c48760990273653a4900de89c7537ffe1b0d6097ed39/rpds_py-0.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:62ac3d4e3e07b58ee0ddecd71d6ce3b1637de2d373501412df395a0ec5f9beb5", size = 353210, upload-time = "2025-08-27T12:12:49.187Z" }, + { url = "https://files.pythonhosted.org/packages/3a/57/f5eb3ecf434342f4f1a46009530e93fd201a0b5b83379034ebdb1d7c1a58/rpds_py-0.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4708c5c0ceb2d034f9991623631d3d23cb16e65c83736ea020cdbe28d57c0a0e", size = 381636, upload-time = "2025-08-27T12:12:50.492Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f4/ef95c5945e2ceb5119571b184dd5a1cc4b8541bbdf67461998cfeac9cb1e/rpds_py-0.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:abfa1171a9952d2e0002aba2ad3780820b00cc3d9c98c6630f2e93271501f66c", size = 394341, upload-time = "2025-08-27T12:12:52.024Z" }, + { url = "https://files.pythonhosted.org/packages/5a/7e/4bd610754bf492d398b61725eb9598ddd5eb86b07d7d9483dbcd810e20bc/rpds_py-0.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b507d19f817ebaca79574b16eb2ae412e5c0835542c93fe9983f1e432aca195", size = 523428, upload-time = "2025-08-27T12:12:53.779Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e5/059b9f65a8c9149361a8b75094864ab83b94718344db511fd6117936ed2a/rpds_py-0.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168b025f8fd8d8d10957405f3fdcef3dc20f5982d398f90851f4abc58c566c52", size = 402923, upload-time = "2025-08-27T12:12:55.15Z" }, + { url = "https://files.pythonhosted.org/packages/f5/48/64cabb7daced2968dd08e8a1b7988bf358d7bd5bcd5dc89a652f4668543c/rpds_py-0.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb56c6210ef77caa58e16e8c17d35c63fe3f5b60fd9ba9d424470c3400bcf9ed", size = 384094, upload-time = "2025-08-27T12:12:57.194Z" }, + { url = "https://files.pythonhosted.org/packages/ae/e1/dc9094d6ff566bff87add8a510c89b9e158ad2ecd97ee26e677da29a9e1b/rpds_py-0.27.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:d252f2d8ca0195faa707f8eb9368955760880b2b42a8ee16d382bf5dd807f89a", size = 401093, upload-time = "2025-08-27T12:12:58.985Z" }, + { url = "https://files.pythonhosted.org/packages/37/8e/ac8577e3ecdd5593e283d46907d7011618994e1d7ab992711ae0f78b9937/rpds_py-0.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6e5e54da1e74b91dbc7996b56640f79b195d5925c2b78efaa8c5d53e1d88edde", size = 417969, upload-time = "2025-08-27T12:13:00.367Z" }, + { url = "https://files.pythonhosted.org/packages/66/6d/87507430a8f74a93556fe55c6485ba9c259949a853ce407b1e23fea5ba31/rpds_py-0.27.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ffce0481cc6e95e5b3f0a47ee17ffbd234399e6d532f394c8dce320c3b089c21", size = 558302, upload-time = "2025-08-27T12:13:01.737Z" }, + { url = "https://files.pythonhosted.org/packages/3a/bb/1db4781ce1dda3eecc735e3152659a27b90a02ca62bfeea17aee45cc0fbc/rpds_py-0.27.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a205fdfe55c90c2cd8e540ca9ceba65cbe6629b443bc05db1f590a3db8189ff9", size = 589259, upload-time = "2025-08-27T12:13:03.127Z" }, + { url = "https://files.pythonhosted.org/packages/7b/0e/ae1c8943d11a814d01b482e1f8da903f88047a962dff9bbdadf3bd6e6fd1/rpds_py-0.27.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:689fb5200a749db0415b092972e8eba85847c23885c8543a8b0f5c009b1a5948", size = 554983, upload-time = "2025-08-27T12:13:04.516Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/0b2a55415931db4f112bdab072443ff76131b5ac4f4dc98d10d2d357eb03/rpds_py-0.27.1-cp311-cp311-win32.whl", hash = "sha256:3182af66048c00a075010bc7f4860f33913528a4b6fc09094a6e7598e462fe39", size = 217154, upload-time = "2025-08-27T12:13:06.278Z" }, + { url = "https://files.pythonhosted.org/packages/24/75/3b7ffe0d50dc86a6a964af0d1cc3a4a2cdf437cb7b099a4747bbb96d1819/rpds_py-0.27.1-cp311-cp311-win_amd64.whl", hash = "sha256:b4938466c6b257b2f5c4ff98acd8128ec36b5059e5c8f8372d79316b1c36bb15", size = 228627, upload-time = "2025-08-27T12:13:07.625Z" }, + { url = "https://files.pythonhosted.org/packages/8d/3f/4fd04c32abc02c710f09a72a30c9a55ea3cc154ef8099078fd50a0596f8e/rpds_py-0.27.1-cp311-cp311-win_arm64.whl", hash = "sha256:2f57af9b4d0793e53266ee4325535a31ba48e2f875da81a9177c9926dfa60746", size = 220998, upload-time = "2025-08-27T12:13:08.972Z" }, + { url = "https://files.pythonhosted.org/packages/bd/fe/38de28dee5df58b8198c743fe2bea0c785c6d40941b9950bac4cdb71a014/rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90", size = 361887, upload-time = "2025-08-27T12:13:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/4b6c7eedc7dd90986bf0fab6ea2a091ec11c01b15f8ba0a14d3f80450468/rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5", size = 345795, upload-time = "2025-08-27T12:13:11.65Z" }, + { url = "https://files.pythonhosted.org/packages/6f/0e/e650e1b81922847a09cca820237b0edee69416a01268b7754d506ade11ad/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e", size = 385121, upload-time = "2025-08-27T12:13:13.008Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ea/b306067a712988e2bff00dcc7c8f31d26c29b6d5931b461aa4b60a013e33/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881", size = 398976, upload-time = "2025-08-27T12:13:14.368Z" }, + { url = "https://files.pythonhosted.org/packages/2c/0a/26dc43c8840cb8fe239fe12dbc8d8de40f2365e838f3d395835dde72f0e5/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec", size = 525953, upload-time = "2025-08-27T12:13:15.774Z" }, + { url = "https://files.pythonhosted.org/packages/22/14/c85e8127b573aaf3a0cbd7fbb8c9c99e735a4a02180c84da2a463b766e9e/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb", size = 407915, upload-time = "2025-08-27T12:13:17.379Z" }, + { url = "https://files.pythonhosted.org/packages/ed/7b/8f4fee9ba1fb5ec856eb22d725a4efa3deb47f769597c809e03578b0f9d9/rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5", size = 386883, upload-time = "2025-08-27T12:13:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/86/47/28fa6d60f8b74fcdceba81b272f8d9836ac0340570f68f5df6b41838547b/rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a", size = 405699, upload-time = "2025-08-27T12:13:20.089Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fd/c5987b5e054548df56953a21fe2ebed51fc1ec7c8f24fd41c067b68c4a0a/rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444", size = 423713, upload-time = "2025-08-27T12:13:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ba/3c4978b54a73ed19a7d74531be37a8bcc542d917c770e14d372b8daea186/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a", size = 562324, upload-time = "2025-08-27T12:13:22.789Z" }, + { url = "https://files.pythonhosted.org/packages/b5/6c/6943a91768fec16db09a42b08644b960cff540c66aab89b74be6d4a144ba/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1", size = 593646, upload-time = "2025-08-27T12:13:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/11/73/9d7a8f4be5f4396f011a6bb7a19fe26303a0dac9064462f5651ced2f572f/rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998", size = 558137, upload-time = "2025-08-27T12:13:25.557Z" }, + { url = "https://files.pythonhosted.org/packages/6e/96/6772cbfa0e2485bcceef8071de7821f81aeac8bb45fbfd5542a3e8108165/rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39", size = 221343, upload-time = "2025-08-27T12:13:26.967Z" }, + { url = "https://files.pythonhosted.org/packages/67/b6/c82f0faa9af1c6a64669f73a17ee0eeef25aff30bb9a1c318509efe45d84/rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594", size = 232497, upload-time = "2025-08-27T12:13:28.326Z" }, + { url = "https://files.pythonhosted.org/packages/e1/96/2817b44bd2ed11aebacc9251da03689d56109b9aba5e311297b6902136e2/rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502", size = 222790, upload-time = "2025-08-27T12:13:29.71Z" }, + { url = "https://files.pythonhosted.org/packages/cc/77/610aeee8d41e39080c7e14afa5387138e3c9fa9756ab893d09d99e7d8e98/rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b", size = 361741, upload-time = "2025-08-27T12:13:31.039Z" }, + { url = "https://files.pythonhosted.org/packages/3a/fc/c43765f201c6a1c60be2043cbdb664013def52460a4c7adace89d6682bf4/rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf", size = 345574, upload-time = "2025-08-27T12:13:32.902Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/ee2b2ca114294cd9847d0ef9c26d2b0851b2e7e00bf14cc4c0b581df0fc3/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83", size = 385051, upload-time = "2025-08-27T12:13:34.228Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e8/1e430fe311e4799e02e2d1af7c765f024e95e17d651612425b226705f910/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf", size = 398395, upload-time = "2025-08-27T12:13:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/82/95/9dc227d441ff2670651c27a739acb2535ccaf8b351a88d78c088965e5996/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2", size = 524334, upload-time = "2025-08-27T12:13:37.562Z" }, + { url = "https://files.pythonhosted.org/packages/87/01/a670c232f401d9ad461d9a332aa4080cd3cb1d1df18213dbd0d2a6a7ab51/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0", size = 407691, upload-time = "2025-08-27T12:13:38.94Z" }, + { url = "https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418", size = 386868, upload-time = "2025-08-27T12:13:40.192Z" }, + { url = "https://files.pythonhosted.org/packages/3b/03/8c897fb8b5347ff6c1cc31239b9611c5bf79d78c984430887a353e1409a1/rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d", size = 405469, upload-time = "2025-08-27T12:13:41.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/07/88c60edc2df74850d496d78a1fdcdc7b54360a7f610a4d50008309d41b94/rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274", size = 422125, upload-time = "2025-08-27T12:13:42.802Z" }, + { url = "https://files.pythonhosted.org/packages/6b/86/5f4c707603e41b05f191a749984f390dabcbc467cf833769b47bf14ba04f/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd", size = 562341, upload-time = "2025-08-27T12:13:44.472Z" }, + { url = "https://files.pythonhosted.org/packages/b2/92/3c0cb2492094e3cd9baf9e49bbb7befeceb584ea0c1a8b5939dca4da12e5/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2", size = 592511, upload-time = "2025-08-27T12:13:45.898Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/82e64fbb0047c46a168faa28d0d45a7851cd0582f850b966811d30f67ad8/rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002", size = 557736, upload-time = "2025-08-27T12:13:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/00/95/3c863973d409210da7fb41958172c6b7dbe7fc34e04d3cc1f10bb85e979f/rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3", size = 221462, upload-time = "2025-08-27T12:13:48.742Z" }, + { url = "https://files.pythonhosted.org/packages/ce/2c/5867b14a81dc217b56d95a9f2a40fdbc56a1ab0181b80132beeecbd4b2d6/rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83", size = 232034, upload-time = "2025-08-27T12:13:50.11Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/3958f3f018c01923823f1e47f1cc338e398814b92d83cd278364446fac66/rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d", size = 222392, upload-time = "2025-08-27T12:13:52.587Z" }, + { url = "https://files.pythonhosted.org/packages/01/76/1cdf1f91aed5c3a7bf2eba1f1c4e4d6f57832d73003919a20118870ea659/rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228", size = 358355, upload-time = "2025-08-27T12:13:54.012Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6f/bf142541229374287604caf3bb2a4ae17f0a580798fd72d3b009b532db4e/rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92", size = 342138, upload-time = "2025-08-27T12:13:55.791Z" }, + { url = "https://files.pythonhosted.org/packages/1a/77/355b1c041d6be40886c44ff5e798b4e2769e497b790f0f7fd1e78d17e9a8/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2", size = 380247, upload-time = "2025-08-27T12:13:57.683Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a4/d9cef5c3946ea271ce2243c51481971cd6e34f21925af2783dd17b26e815/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723", size = 390699, upload-time = "2025-08-27T12:13:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/3a/06/005106a7b8c6c1a7e91b73169e49870f4af5256119d34a361ae5240a0c1d/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802", size = 521852, upload-time = "2025-08-27T12:14:00.583Z" }, + { url = "https://files.pythonhosted.org/packages/e5/3e/50fb1dac0948e17a02eb05c24510a8fe12d5ce8561c6b7b7d1339ab7ab9c/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f", size = 402582, upload-time = "2025-08-27T12:14:02.034Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/f4e224090dc5b0ec15f31a02d746ab24101dd430847c4d99123798661bfc/rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2", size = 384126, upload-time = "2025-08-27T12:14:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/54/77/ac339d5f82b6afff1df8f0fe0d2145cc827992cb5f8eeb90fc9f31ef7a63/rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21", size = 399486, upload-time = "2025-08-27T12:14:05.443Z" }, + { url = "https://files.pythonhosted.org/packages/d6/29/3e1c255eee6ac358c056a57d6d6869baa00a62fa32eea5ee0632039c50a3/rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef", size = 414832, upload-time = "2025-08-27T12:14:06.902Z" }, + { url = "https://files.pythonhosted.org/packages/3f/db/6d498b844342deb3fa1d030598db93937a9964fcf5cb4da4feb5f17be34b/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081", size = 557249, upload-time = "2025-08-27T12:14:08.37Z" }, + { url = "https://files.pythonhosted.org/packages/60/f3/690dd38e2310b6f68858a331399b4d6dbb9132c3e8ef8b4333b96caf403d/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd", size = 587356, upload-time = "2025-08-27T12:14:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/86/e3/84507781cccd0145f35b1dc32c72675200c5ce8d5b30f813e49424ef68fc/rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7", size = 555300, upload-time = "2025-08-27T12:14:11.783Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ee/375469849e6b429b3516206b4580a79e9ef3eb12920ddbd4492b56eaacbe/rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688", size = 216714, upload-time = "2025-08-27T12:14:13.629Z" }, + { url = "https://files.pythonhosted.org/packages/21/87/3fc94e47c9bd0742660e84706c311a860dcae4374cf4a03c477e23ce605a/rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797", size = 228943, upload-time = "2025-08-27T12:14:14.937Z" }, + { url = "https://files.pythonhosted.org/packages/70/36/b6e6066520a07cf029d385de869729a895917b411e777ab1cde878100a1d/rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334", size = 362472, upload-time = "2025-08-27T12:14:16.333Z" }, + { url = "https://files.pythonhosted.org/packages/af/07/b4646032e0dcec0df9c73a3bd52f63bc6c5f9cda992f06bd0e73fe3fbebd/rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33", size = 345676, upload-time = "2025-08-27T12:14:17.764Z" }, + { url = "https://files.pythonhosted.org/packages/b0/16/2f1003ee5d0af4bcb13c0cf894957984c32a6751ed7206db2aee7379a55e/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a", size = 385313, upload-time = "2025-08-27T12:14:19.829Z" }, + { url = "https://files.pythonhosted.org/packages/05/cd/7eb6dd7b232e7f2654d03fa07f1414d7dfc980e82ba71e40a7c46fd95484/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b", size = 399080, upload-time = "2025-08-27T12:14:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/20/51/5829afd5000ec1cb60f304711f02572d619040aa3ec033d8226817d1e571/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7", size = 523868, upload-time = "2025-08-27T12:14:23.485Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/30eebca20d5db95720ab4d2faec1b5e4c1025c473f703738c371241476a2/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136", size = 408750, upload-time = "2025-08-27T12:14:24.924Z" }, + { url = "https://files.pythonhosted.org/packages/90/1a/cdb5083f043597c4d4276eae4e4c70c55ab5accec078da8611f24575a367/rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff", size = 387688, upload-time = "2025-08-27T12:14:27.537Z" }, + { url = "https://files.pythonhosted.org/packages/7c/92/cf786a15320e173f945d205ab31585cc43969743bb1a48b6888f7a2b0a2d/rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9", size = 407225, upload-time = "2025-08-27T12:14:28.981Z" }, + { url = "https://files.pythonhosted.org/packages/33/5c/85ee16df5b65063ef26017bef33096557a4c83fbe56218ac7cd8c235f16d/rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60", size = 423361, upload-time = "2025-08-27T12:14:30.469Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8e/1c2741307fcabd1a334ecf008e92c4f47bb6f848712cf15c923becfe82bb/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e", size = 562493, upload-time = "2025-08-27T12:14:31.987Z" }, + { url = "https://files.pythonhosted.org/packages/04/03/5159321baae9b2222442a70c1f988cbbd66b9be0675dd3936461269be360/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212", size = 592623, upload-time = "2025-08-27T12:14:33.543Z" }, + { url = "https://files.pythonhosted.org/packages/ff/39/c09fd1ad28b85bc1d4554a8710233c9f4cefd03d7717a1b8fbfd171d1167/rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675", size = 558800, upload-time = "2025-08-27T12:14:35.436Z" }, + { url = "https://files.pythonhosted.org/packages/c5/d6/99228e6bbcf4baa764b18258f519a9035131d91b538d4e0e294313462a98/rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3", size = 221943, upload-time = "2025-08-27T12:14:36.898Z" }, + { url = "https://files.pythonhosted.org/packages/be/07/c802bc6b8e95be83b79bdf23d1aa61d68324cb1006e245d6c58e959e314d/rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456", size = 233739, upload-time = "2025-08-27T12:14:38.386Z" }, + { url = "https://files.pythonhosted.org/packages/c8/89/3e1b1c16d4c2d547c5717377a8df99aee8099ff050f87c45cb4d5fa70891/rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3", size = 223120, upload-time = "2025-08-27T12:14:39.82Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/dc7931dc2fa4a6e46b2a4fa744a9fe5c548efd70e0ba74f40b39fa4a8c10/rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2", size = 358944, upload-time = "2025-08-27T12:14:41.199Z" }, + { url = "https://files.pythonhosted.org/packages/e6/22/4af76ac4e9f336bfb1a5f240d18a33c6b2fcaadb7472ac7680576512b49a/rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4", size = 342283, upload-time = "2025-08-27T12:14:42.699Z" }, + { url = "https://files.pythonhosted.org/packages/1c/15/2a7c619b3c2272ea9feb9ade67a45c40b3eeb500d503ad4c28c395dc51b4/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e", size = 380320, upload-time = "2025-08-27T12:14:44.157Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7d/4c6d243ba4a3057e994bb5bedd01b5c963c12fe38dde707a52acdb3849e7/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817", size = 391760, upload-time = "2025-08-27T12:14:45.845Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/b19401a909b83bcd67f90221330bc1ef11bc486fe4e04c24388d28a618ae/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec", size = 522476, upload-time = "2025-08-27T12:14:47.364Z" }, + { url = "https://files.pythonhosted.org/packages/e4/44/1a3b9715c0455d2e2f0f6df5ee6d6f5afdc423d0773a8a682ed2b43c566c/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a", size = 403418, upload-time = "2025-08-27T12:14:49.991Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4b/fb6c4f14984eb56673bc868a66536f53417ddb13ed44b391998100a06a96/rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8", size = 384771, upload-time = "2025-08-27T12:14:52.159Z" }, + { url = "https://files.pythonhosted.org/packages/c0/56/d5265d2d28b7420d7b4d4d85cad8ef891760f5135102e60d5c970b976e41/rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48", size = 400022, upload-time = "2025-08-27T12:14:53.859Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/9f5fc70164a569bdd6ed9046486c3568d6926e3a49bdefeeccfb18655875/rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb", size = 416787, upload-time = "2025-08-27T12:14:55.673Z" }, + { url = "https://files.pythonhosted.org/packages/d4/64/56dd03430ba491db943a81dcdef115a985aac5f44f565cd39a00c766d45c/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734", size = 557538, upload-time = "2025-08-27T12:14:57.245Z" }, + { url = "https://files.pythonhosted.org/packages/3f/36/92cc885a3129993b1d963a2a42ecf64e6a8e129d2c7cc980dbeba84e55fb/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb", size = 588512, upload-time = "2025-08-27T12:14:58.728Z" }, + { url = "https://files.pythonhosted.org/packages/dd/10/6b283707780a81919f71625351182b4f98932ac89a09023cb61865136244/rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0", size = 555813, upload-time = "2025-08-27T12:15:00.334Z" }, + { url = "https://files.pythonhosted.org/packages/04/2e/30b5ea18c01379da6272a92825dd7e53dc9d15c88a19e97932d35d430ef7/rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a", size = 217385, upload-time = "2025-08-27T12:15:01.937Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/97119da51cb1dd3f2f3c0805f155a3aa4a95fa44fe7d78ae15e69edf4f34/rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772", size = 230097, upload-time = "2025-08-27T12:15:03.961Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ed/e1fba02de17f4f76318b834425257c8ea297e415e12c68b4361f63e8ae92/rpds_py-0.27.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdfe4bb2f9fe7458b7453ad3c33e726d6d1c7c0a72960bcc23800d77384e42df", size = 371402, upload-time = "2025-08-27T12:15:51.561Z" }, + { url = "https://files.pythonhosted.org/packages/af/7c/e16b959b316048b55585a697e94add55a4ae0d984434d279ea83442e460d/rpds_py-0.27.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8fabb8fd848a5f75a2324e4a84501ee3a5e3c78d8603f83475441866e60b94a3", size = 354084, upload-time = "2025-08-27T12:15:53.219Z" }, + { url = "https://files.pythonhosted.org/packages/de/c1/ade645f55de76799fdd08682d51ae6724cb46f318573f18be49b1e040428/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda8719d598f2f7f3e0f885cba8646644b55a187762bec091fa14a2b819746a9", size = 383090, upload-time = "2025-08-27T12:15:55.158Z" }, + { url = "https://files.pythonhosted.org/packages/1f/27/89070ca9b856e52960da1472efcb6c20ba27cfe902f4f23ed095b9cfc61d/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c64d07e95606ec402a0a1c511fe003873fa6af630bda59bac77fac8b4318ebc", size = 394519, upload-time = "2025-08-27T12:15:57.238Z" }, + { url = "https://files.pythonhosted.org/packages/b3/28/be120586874ef906aa5aeeae95ae8df4184bc757e5b6bd1c729ccff45ed5/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93a2ed40de81bcff59aabebb626562d48332f3d028ca2036f1d23cbb52750be4", size = 523817, upload-time = "2025-08-27T12:15:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ef/70cc197bc11cfcde02a86f36ac1eed15c56667c2ebddbdb76a47e90306da/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:387ce8c44ae94e0ec50532d9cb0edce17311024c9794eb196b90e1058aadeb66", size = 403240, upload-time = "2025-08-27T12:16:00.923Z" }, + { url = "https://files.pythonhosted.org/packages/cf/35/46936cca449f7f518f2f4996e0e8344db4b57e2081e752441154089d2a5f/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf94f812c95b5e60ebaf8bfb1898a7d7cb9c1af5744d4a67fa47796e0465d4e", size = 385194, upload-time = "2025-08-27T12:16:02.802Z" }, + { url = "https://files.pythonhosted.org/packages/e1/62/29c0d3e5125c3270b51415af7cbff1ec587379c84f55a5761cc9efa8cd06/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4848ca84d6ded9b58e474dfdbad4b8bfb450344c0551ddc8d958bf4b36aa837c", size = 402086, upload-time = "2025-08-27T12:16:04.806Z" }, + { url = "https://files.pythonhosted.org/packages/8f/66/03e1087679227785474466fdd04157fb793b3b76e3fcf01cbf4c693c1949/rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bde09cbcf2248b73c7c323be49b280180ff39fadcfe04e7b6f54a678d02a7cf", size = 419272, upload-time = "2025-08-27T12:16:06.471Z" }, + { url = "https://files.pythonhosted.org/packages/6a/24/e3e72d265121e00b063aef3e3501e5b2473cf1b23511d56e529531acf01e/rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:94c44ee01fd21c9058f124d2d4f0c9dc7634bec93cd4b38eefc385dabe71acbf", size = 560003, upload-time = "2025-08-27T12:16:08.06Z" }, + { url = "https://files.pythonhosted.org/packages/26/ca/f5a344c534214cc2d41118c0699fffbdc2c1bc7046f2a2b9609765ab9c92/rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:df8b74962e35c9249425d90144e721eed198e6555a0e22a563d29fe4486b51f6", size = 590482, upload-time = "2025-08-27T12:16:10.137Z" }, + { url = "https://files.pythonhosted.org/packages/ce/08/4349bdd5c64d9d193c360aa9db89adeee6f6682ab8825dca0a3f535f434f/rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:dc23e6820e3b40847e2f4a7726462ba0cf53089512abe9ee16318c366494c17a", size = 556523, upload-time = "2025-08-27T12:16:12.188Z" }, ] [[package]] @@ -2950,14 +2922,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/9c/44314fcd4816367084e6df7698508b397d683f63b0d7b5acd86003b7b377/semantic_kernel-1.35.3-py3-none-any.whl", hash = "sha256:11c97405530c1c266df8589f3c0775e7fab7b92b17df19e0dfaee44f47cac5fa", size = 882352, upload-time = "2025-08-14T00:34:57.167Z" }, ] -[package.optional-dependencies] -azure = [ - { name = "azure-ai-inference" }, - { name = "azure-core-tracing-opentelemetry" }, - { name = "azure-cosmos" }, - { name = "azure-search-documents" }, -] - [[package]] name = "six" version = "1.17.0" @@ -3063,11 +3027,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.15.0rc1" +version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/d5/1b2b1803ecd99e11a842d054c6b6f3f7938dde30d42b4d0d99611b2ee6fd/typing_extensions-4.15.0rc1.tar.gz", hash = "sha256:49b001798e59fbb7a523f0d36e8cf2d82d8e3f9fc41b04ff958da1ed7cc3b671", size = 109126, upload-time = "2025-08-18T14:31:09.022Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/61/1e821439fa89ca57c8a31e285742b7aeb719c8068e06074717b398642fb7/typing_extensions-4.15.0rc1-py3-none-any.whl", hash = "sha256:8fd4191376831cd3503df0cf06a0c0e6c1dae08ea3e6af770a785eeb90934dea", size = 44640, upload-time = "2025-08-18T14:31:07.386Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] diff --git a/src/frontend/frontend_server.py b/src/frontend/frontend_server.py index 56651e0a1..bfa152e3c 100644 --- a/src/frontend/frontend_server.py +++ b/src/frontend/frontend_server.py @@ -50,13 +50,14 @@ async def get_config(): @app.get("/{full_path:path}") async def serve_app(full_path: str): - # First check if file exists in build directory - file_path = os.path.join(BUILD_DIR, full_path) - if os.path.exists(file_path): + # Remediation: normalize and check containment before serving + file_path = os.path.normpath(os.path.join(BUILD_DIR, full_path)) + # Block traversal and dotfiles + if not file_path.startswith(BUILD_DIR) or ".." in full_path or "/." in full_path or "\\." in full_path: + return FileResponse(INDEX_HTML) + if os.path.isfile(file_path): return FileResponse(file_path) - # Otherwise serve index.html for client-side routing return FileResponse(INDEX_HTML) - if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=3000) diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index f857405d3..ec6f9314f 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -19,7 +19,7 @@ "@types/node": "^16.18.126", "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", - "axios": "^1.9.0", + "axios": "^1.11.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-markdown": "^10.1.0", @@ -36,16 +36,16 @@ "@vitest/ui": "^3.2.4", "eslint": "^8.57.1", "eslint-plugin-react": "^7.37.5", - "jsdom": "^24.1.3", + "jsdom": "^26.1.0", "typescript": "^5.8.3", "vite": "^7.1.2", "vitest": "^3.2.4" } }, "node_modules/@adobe/css-tools": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", - "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==", + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", "license": "MIT" }, "node_modules/@ampproject/remapping": { @@ -98,9 +98,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz", - "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "dev": true, "license": "MIT", "engines": { @@ -108,22 +108,22 @@ } }, "node_modules/@babel/core": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz", - "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", + "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.4", - "@babel/parser": "^7.27.4", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.27.4", - "@babel/types": "^7.27.3", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -149,16 +149,16 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", - "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.5", - "@babel/types": "^7.27.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -192,6 +192,16 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", @@ -207,15 +217,15 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", - "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.27.3" + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -264,27 +274,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", - "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", + "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", - "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.28.2" }, "bin": { "parser": "bin/babel-parser.js" @@ -326,9 +336,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", - "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", + "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -350,28 +360,28 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz", - "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", - "@babel/parser": "^7.27.4", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", "@babel/template": "^7.27.2", - "@babel/types": "^7.27.3", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/types": "^7.28.2", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", - "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1007,22 +1017,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", @@ -1034,36 +1028,37 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.1.tgz", - "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.9" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/devtools": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.1.tgz", - "integrity": "sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.3.tgz", + "integrity": "sha512-ZTcxTvgo9CRlP7vJV62yCxdqmahHTGpSTi5QaTDgGoyQq0OyjaVZhUhXv/qdkQFOI3Sxlfmz0XGG4HaZMsDf8Q==", + "license": "MIT", "peerDependencies": { - "@floating-ui/dom": ">=1.5.4" + "@floating-ui/dom": "^1.0.0" } }, "node_modules/@floating-ui/dom": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.1.tgz", - "integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.1", - "@floating-ui/utils": "^0.2.9" + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", - "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, "node_modules/@fluentui/keyboard-keys": { @@ -1095,21 +1090,21 @@ } }, "node_modules/@fluentui/react-accordion": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.7.0.tgz", - "integrity": "sha512-DzWK3RBWlREn9EUYEXdYZhC6cjJLAm2u21qqofovrIlU/LDUUCC1cPxJHycdi9KwP7mDZdhXSqQG6LLe9xIeMQ==", + "version": "9.8.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.8.5.tgz", + "integrity": "sha512-e3RNtrzTgTRSwueOaxjQimG3u8QQUa8EiTIpRThadedleVtS0KWfuvSv2/EKUL85I6toaTthOFFuJRpP6C9Frw==", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-motion": "^9.8.0", - "@fluentui/react-motion-components-preview": "^0.6.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-motion": "^9.10.3", + "@fluentui/react-motion-components-preview": "^0.9.0", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1144,16 +1139,16 @@ } }, "node_modules/@fluentui/react-aria": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.15.0.tgz", - "integrity": "sha512-8cN9/5+XHL3mzp1gNIj0ZXuPTioYALO/1FCWugkOF5JP8PVkV3HDX3ezRq2Bk44PS2YK98tjffTiBzFeanHxug==", + "version": "9.16.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.16.4.tgz", + "integrity": "sha512-ent+vc93+6EAeg26tnZMoRp8lIJtfFMbKFAa0WvZGbN5jU24NQUniJCdXcsfrmVCQ2hHophQDvUSwGhPkABURw==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-utilities": "^9.24.0", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -1164,21 +1159,21 @@ } }, "node_modules/@fluentui/react-avatar": { - "version": "9.8.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.8.1.tgz", - "integrity": "sha512-hLOFxN8oqRkO8lBqGhXLONtI4LRWf/16TJDiizWbfep33NMS/rpHl+PijwO873CXRxSDnR1z3sENHpVInILtug==", + "version": "9.9.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.9.5.tgz", + "integrity": "sha512-xl1oewoY7dtNCyEuhghJCzHF1RVARZdtVsuleMvI9TZuyjoKuXyOzaLSyFhh1lXGkcrSsS3JtrVrTVFyR2u/wg==", "license": "MIT", "dependencies": { - "@fluentui/react-badge": "^9.3.0", - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/react-badge": "^9.4.4", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-popover": "^9.11.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-tooltip": "^9.7.1", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-popover": "^9.12.5", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-tooltip": "^9.8.4", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1190,16 +1185,16 @@ } }, "node_modules/@fluentui/react-badge": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.3.0.tgz", - "integrity": "sha512-BFONtrI0SZmM+j+wR8tb5S43qodY5AydKMCJ35e02rR1/nyizg4tA3g/3iujGHAAsXPX04D20W4QMcy9LyRAXA==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.4.4.tgz", + "integrity": "sha512-XfAwIweS9ypwkNsWfEApM6xLAqAJjgC4Vb31owRqUBGu+IKlKDLqhNKQPyTLVb8Ql+okiEFu7tZellCRr5K1Uw==", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1211,20 +1206,20 @@ } }, "node_modules/@fluentui/react-breadcrumb": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.2.1.tgz", - "integrity": "sha512-xwrwLz8AbvfcbESviNOrQD4GZ8YeabDK/WLzVXPf+sWsnPnnYx+j/+EgnsbTjJ8FtYKkak1pMq6KwLC1mzWQnQ==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.3.5.tgz", + "integrity": "sha512-AkBMEo1L81wH5UYTQs6QqOFiAbAF9xrA6V7CDSfzOO0yBAlQH5N4DD6b+Q8dEDBWPfUmy15VzYVmhQosm4Tztg==", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-button": "^9.5.0", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-button": "^9.6.5", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-link": "^9.5.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-link": "^9.6.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1236,19 +1231,19 @@ } }, "node_modules/@fluentui/react-button": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.5.0.tgz", - "integrity": "sha512-J4Tdxcey6cjyxKuRAQkUynAwBwLnuTmGry9APGddbnGPGXBDNqjHIqqMDua5lOSIINSIiQHTNdg7fZWoETSZ4Q==", + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.6.5.tgz", + "integrity": "sha512-UMhGNn82rhz4o9dAVVG/4OUI7XjZlUW4F2u8BkSh0RAUD+d3wQn4EFYSF7/VbLvdq+dgLIaCTUMkd1UerDRvYw==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", + "@fluentui/react-aria": "^9.16.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1260,18 +1255,18 @@ } }, "node_modules/@fluentui/react-card": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.3.0.tgz", - "integrity": "sha512-ZvCuFta3X2HaLTU0fdpbHCz/j+jGYRhwC0CVcxK1u4cXb74r4V2DfXaNYI9vXw9ELGe3YoiOE7xmDdDL0sRUYQ==", + "version": "9.4.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.4.5.tgz", + "integrity": "sha512-MFsbbT38AzjvAdvFlPGetPV01FJTlPf3cC/UiKmR4nhZg2ss2H4+jh0p4Y/xHSCUUe5Q5nMtVX0+xSUrEt+Lig==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-text": "^9.5.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-text": "^9.6.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1282,45 +1277,27 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-checkbox": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.4.1.tgz", - "integrity": "sha512-lrf4I12fGMrodQODjrwTgDl5bOssXuEzg+ioMh/ldWQGD6xPjoqrznLusfjj+Ua1qR6k2bHnHuSDoH7E1vzlng==", + "node_modules/@fluentui/react-carousel": { + "version": "9.8.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-carousel/-/react-carousel-9.8.5.tgz", + "integrity": "sha512-mSgUvznEzBGhJ3PRX8BQGILbD/C0UiKul0Ry79h3y/0A8TGm8wVFDzXOH0QQsugOio4JpUamm/fDApHodsMVmw==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-button": "^9.6.5", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-label": "^9.2.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", - "@griffel/react": "^1.5.22", - "@swc/helpers": "^0.5.1" - }, - "peerDependencies": { - "@types/react": ">=16.14.0 <19.0.0", - "@types/react-dom": ">=16.9.0 <19.0.0", - "react": ">=16.14.0 <19.0.0", - "react-dom": ">=16.14.0 <19.0.0" - } - }, - "node_modules/@fluentui/react-color-picker": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-color-picker/-/react-color-picker-9.1.0.tgz", - "integrity": "sha512-Tm85dMk0XPUZDCybjd0sa+1txR38ejLL+MG/Z03cpC41GxihDh5+4dPAqSfPzfezbENNoFsqfjKiKhw0Un96Rg==", - "license": "MIT", - "dependencies": { - "@ctrl/tinycolor": "^3.3.4", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-tooltip": "^9.8.4", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", - "@swc/helpers": "^0.5.1" + "@swc/helpers": "^0.5.1", + "embla-carousel": "^8.5.1", + "embla-carousel-autoplay": "^8.5.1", + "embla-carousel-fade": "^8.5.1" }, "peerDependencies": { "@types/react": ">=16.14.0 <19.0.0", @@ -1329,24 +1306,20 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-combobox": { - "version": "9.15.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.15.1.tgz", - "integrity": "sha512-/WmfxkrYwe3/XU4gan56tjEBVdBmG43tW247vqXHQiC/e3q/dsqwQNhCO/VVr2pTS/Y3xhorMML63Azh9WXJ4A==", + "node_modules/@fluentui/react-checkbox": { + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.5.4.tgz", + "integrity": "sha512-1OcjlGAOhtv67aUcHHXCFFO2Phmps30NcagQX1PhDjQNWCQa8k3de6obpgTNfLvD6EA8K0Yz+x4BkpwK11DxGQ==", "license": "MIT", "dependencies": { - "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-field": "^9.3.1", + "@fluentui/react-field": "^9.4.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-positioning": "^9.18.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-label": "^9.3.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1357,72 +1330,19 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-components": { - "version": "9.66.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.66.1.tgz", - "integrity": "sha512-Rzh+QL2reQEMaFLu+h314ic7w8W9TbDcyDpohb+CRODgT3YCw+Gt+SVbR3Yi+8Cf3kwtokDQIC3ki6iBQ9g/Tg==", + "node_modules/@fluentui/react-color-picker": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-color-picker/-/react-color-picker-9.2.4.tgz", + "integrity": "sha512-LjjwfUvD0TyWTJnAIZgpgDwLj3HtBGcW4ZlM0AllJN8q3RnxnEA5ygFrhB2bFjOc6a4ijCavKEU5ZfdtmS+Kpg==", "license": "MIT", "dependencies": { - "@fluentui/react-accordion": "^9.7.0", - "@fluentui/react-alert": "9.0.0-beta.124", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-avatar": "^9.8.1", - "@fluentui/react-badge": "^9.3.0", - "@fluentui/react-breadcrumb": "^9.2.1", - "@fluentui/react-button": "^9.5.0", - "@fluentui/react-card": "^9.3.0", - "@fluentui/react-carousel": "^9.7.1", - "@fluentui/react-checkbox": "^9.4.1", - "@fluentui/react-color-picker": "^9.1.0", - "@fluentui/react-combobox": "^9.15.1", - "@fluentui/react-dialog": "^9.13.1", - "@fluentui/react-divider": "^9.3.0", - "@fluentui/react-drawer": "^9.8.1", - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-image": "^9.2.0", - "@fluentui/react-infobutton": "9.0.0-beta.102", - "@fluentui/react-infolabel": "^9.3.1", - "@fluentui/react-input": "^9.6.1", - "@fluentui/react-label": "^9.2.0", - "@fluentui/react-link": "^9.5.0", - "@fluentui/react-list": "^9.2.1", - "@fluentui/react-menu": "^9.17.1", - "@fluentui/react-message-bar": "^9.5.0", - "@fluentui/react-motion": "^9.8.0", - "@fluentui/react-nav": "^9.1.1", - "@fluentui/react-overflow": "^9.4.1", - "@fluentui/react-persona": "^9.4.1", - "@fluentui/react-popover": "^9.11.1", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-positioning": "^9.18.1", - "@fluentui/react-progress": "^9.3.1", - "@fluentui/react-provider": "^9.21.0", - "@fluentui/react-radio": "^9.4.1", - "@fluentui/react-rating": "^9.2.0", - "@fluentui/react-search": "^9.2.1", - "@fluentui/react-select": "^9.3.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-skeleton": "^9.3.1", - "@fluentui/react-slider": "^9.4.1", - "@fluentui/react-spinbutton": "^9.4.1", - "@fluentui/react-spinner": "^9.6.0", - "@fluentui/react-swatch-picker": "^9.3.1", - "@fluentui/react-switch": "^9.3.1", - "@fluentui/react-table": "^9.17.1", - "@fluentui/react-tabs": "^9.8.0", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-tag-picker": "^9.6.1", - "@fluentui/react-tags": "^9.6.1", - "@fluentui/react-teaching-popover": "^9.5.1", - "@fluentui/react-text": "^9.5.0", - "@fluentui/react-textarea": "^9.5.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-toast": "^9.5.0", - "@fluentui/react-toolbar": "^9.5.1", - "@fluentui/react-tooltip": "^9.7.1", - "@fluentui/react-tree": "^9.11.1", - "@fluentui/react-utilities": "^9.21.0", - "@fluentui/react-virtualizer": "9.0.0-alpha.98", + "@ctrl/tinycolor": "^3.3.4", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1433,49 +1353,24 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-components/node_modules/@fluentui/react-carousel": { - "version": "9.7.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-carousel/-/react-carousel-9.7.1.tgz", - "integrity": "sha512-nmr1QCzH5vZHZ6KQ50YK+1obfKr/hejgqSMu1Ze/CwZ2/louEYzN2bhibtJfW6b3PpBeowL+S26jbdNWtI78yg==", + "node_modules/@fluentui/react-combobox": { + "version": "9.16.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.16.5.tgz", + "integrity": "sha512-hgBru9DW1XIysbfk7RsnfhwoxQ8JpaAFoPZF16sAtkM2W+WpBYWcHHnYHbntCos1TB2yDKCdOfkQDaHwgOUeQw==", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-button": "^9.5.0", - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-field": "^9.4.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-tooltip": "^9.7.1", - "@fluentui/react-utilities": "^9.21.0", - "@griffel/react": "^1.5.22", - "@swc/helpers": "^0.5.1", - "embla-carousel": "^8.5.1", - "embla-carousel-autoplay": "^8.5.1", - "embla-carousel-fade": "^8.5.1" - }, - "peerDependencies": { - "@types/react": ">=16.14.0 <19.0.0", - "@types/react-dom": ">=16.9.0 <19.0.0", - "react": ">=16.14.0 <19.0.0", - "react-dom": ">=16.14.0 <19.0.0" - } - }, - "node_modules/@fluentui/react-components/node_modules/@fluentui/react-drawer": { - "version": "9.8.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.8.1.tgz", - "integrity": "sha512-VjzG0qAXN7eXiBbFzM7YHpNes05YIdY3WHJD6V2FheHvmthzhw8GFqDnRHsZ581Wb9uB9xqi+WJ69vNJ9tS48Q==", - "license": "MIT", - "dependencies": { - "@fluentui/react-dialog": "^9.13.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-motion": "^9.8.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-positioning": "^9.20.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1486,26 +1381,72 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-components/node_modules/@fluentui/react-tag-picker": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-tag-picker/-/react-tag-picker-9.6.1.tgz", - "integrity": "sha512-eQJHWpc8IfA/D/tsJZ2LOrPsm3CykRrRwIOl4qmRpxGF7jpjc9TTgv/x65xhNAV1zlHkn/kdeF3c6fg51ZPZYQ==", + "node_modules/@fluentui/react-components": { + "version": "9.69.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.69.0.tgz", + "integrity": "sha512-iw6gZVdAMPgPLbAwwAcA+2wRfeHdV27tRMPfrNYnFlXMAYfcXQvWjxeD8XTL5j2PYfOhRJjnWvjL0srJjjMcfA==", "license": "MIT", "dependencies": { - "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-combobox": "^9.15.1", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-positioning": "^9.18.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-tags": "^9.6.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-accordion": "^9.8.5", + "@fluentui/react-alert": "9.0.0-beta.124", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-avatar": "^9.9.5", + "@fluentui/react-badge": "^9.4.4", + "@fluentui/react-breadcrumb": "^9.3.5", + "@fluentui/react-button": "^9.6.5", + "@fluentui/react-card": "^9.4.5", + "@fluentui/react-carousel": "^9.8.5", + "@fluentui/react-checkbox": "^9.5.4", + "@fluentui/react-color-picker": "^9.2.4", + "@fluentui/react-combobox": "^9.16.5", + "@fluentui/react-dialog": "^9.15.0", + "@fluentui/react-divider": "^9.4.4", + "@fluentui/react-drawer": "^9.10.0", + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-image": "^9.3.4", + "@fluentui/react-infobutton": "9.0.0-beta.102", + "@fluentui/react-infolabel": "^9.4.5", + "@fluentui/react-input": "^9.7.4", + "@fluentui/react-label": "^9.3.4", + "@fluentui/react-link": "^9.6.4", + "@fluentui/react-list": "^9.5.0", + "@fluentui/react-menu": "^9.19.5", + "@fluentui/react-message-bar": "^9.6.5", + "@fluentui/react-motion": "^9.10.3", + "@fluentui/react-nav": "^9.3.5", + "@fluentui/react-overflow": "^9.5.5", + "@fluentui/react-persona": "^9.5.5", + "@fluentui/react-popover": "^9.12.5", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-positioning": "^9.20.4", + "@fluentui/react-progress": "^9.4.4", + "@fluentui/react-provider": "^9.22.4", + "@fluentui/react-radio": "^9.5.4", + "@fluentui/react-rating": "^9.3.4", + "@fluentui/react-search": "^9.3.4", + "@fluentui/react-select": "^9.4.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-skeleton": "^9.4.4", + "@fluentui/react-slider": "^9.5.4", + "@fluentui/react-spinbutton": "^9.5.4", + "@fluentui/react-spinner": "^9.7.4", + "@fluentui/react-swatch-picker": "^9.4.4", + "@fluentui/react-switch": "^9.4.4", + "@fluentui/react-table": "^9.18.5", + "@fluentui/react-tabs": "^9.10.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-tag-picker": "^9.7.5", + "@fluentui/react-tags": "^9.7.5", + "@fluentui/react-teaching-popover": "^9.6.5", + "@fluentui/react-text": "^9.6.4", + "@fluentui/react-textarea": "^9.6.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-toast": "^9.7.0", + "@fluentui/react-toolbar": "^9.6.5", + "@fluentui/react-tooltip": "^9.8.4", + "@fluentui/react-tree": "^9.13.0", + "@fluentui/react-utilities": "^9.24.0", + "@fluentui/react-virtualizer": "9.0.0-alpha.102", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1516,67 +1457,41 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-components/node_modules/@fluentui/react-tags": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.6.1.tgz", - "integrity": "sha512-h511CaowCakh1jXWFk7J2iy/7iXie0EafJqSYkES0fD/3whJOdos355veYkUqdD8G7BaMjL5n9Bkj3OjlxrMJw==", + "node_modules/@fluentui/react-context-selector": { + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.2.6.tgz", + "integrity": "sha512-AskFoj248mH8USB/GfXRxj4PbVETVg+T1Xl+uVS6owYchVqkDDHW3oYnZdOTY/rMf1hxOUJhcC3GtXP0JRFdbg==", "license": "MIT", "dependencies": { - "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-avatar": "^9.8.1", - "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", - "@griffel/react": "^1.5.22", + "@fluentui/react-utilities": "^9.24.0", "@swc/helpers": "^0.5.1" }, "peerDependencies": { "@types/react": ">=16.14.0 <19.0.0", "@types/react-dom": ">=16.9.0 <19.0.0", "react": ">=16.14.0 <19.0.0", - "react-dom": ">=16.14.0 <19.0.0" + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" } }, - "node_modules/@fluentui/react-components/node_modules/@fluentui/react-teaching-popover": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-teaching-popover/-/react-teaching-popover-9.5.1.tgz", - "integrity": "sha512-4YUcfbu/y2uY/gJGwo8EwcqegGBaFc6Mt4pKHLgUJd3m+26YDuHFEwpWEN/gHZ1nKsAXg/zlPpaPuDOwzFZFtQ==", + "node_modules/@fluentui/react-dialog": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.15.0.tgz", + "integrity": "sha512-sB8ilho8af0QW+pekkBJRpXaZvh1CQkEUOUdB0UhGWlH0zuRdl3gbMujjh06anVJgeo6bT2yomlG2YPjVLv9Rg==", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-button": "^9.5.0", - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-popover": "^9.11.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", - "@griffel/react": "^1.5.22", - "@swc/helpers": "^0.5.1", - "use-sync-external-store": "^1.2.0" - }, - "peerDependencies": { - "@types/react": ">=16.8.0 <19.0.0", - "@types/react-dom": ">=16.8.0 <19.0.0", - "react": ">=16.14.0 <19.0.0", - "react-dom": ">=16.8.0 <19.0.0" - } - }, - "node_modules/@fluentui/react-components/node_modules/@fluentui/react-virtualizer": { - "version": "9.0.0-alpha.98", - "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.98.tgz", - "integrity": "sha512-BXLXsQPOS+IXrOoH0ZFBbEH6HI7zwGjWoiCPCkqexQYa54flDI8jo2xU7FrvYKVLVNK5oa+UA9jxw5GqDah8QQ==", - "license": "MIT", - "dependencies": { - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-motion": "^9.10.3", + "@fluentui/react-motion-components-preview": "^0.9.0", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1587,41 +1502,16 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-context-selector": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.2.0.tgz", - "integrity": "sha512-s35dNhIcHGm6SmmQr04vATaogQZ2Wvl1zi4/xgZ4/6V8XAGPBqRRTkutjkWgW4u4WZDriWdWNL62ju3hGDpE9g==", - "license": "MIT", - "dependencies": { - "@fluentui/react-utilities": "^9.21.0", - "@swc/helpers": "^0.5.1" - }, - "peerDependencies": { - "@types/react": ">=16.14.0 <19.0.0", - "@types/react-dom": ">=16.9.0 <19.0.0", - "react": ">=16.14.0 <19.0.0", - "react-dom": ">=16.14.0 <19.0.0", - "scheduler": ">=0.19.0 <=0.23.0" - } - }, - "node_modules/@fluentui/react-dialog": { - "version": "9.13.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.13.1.tgz", - "integrity": "sha512-YCGTh4IPaHQH1LTLoD5D5Ql7DK+1ytMHYL4kQ9O8CmSu3WntjUSmOKGxWDHqHLEX0gRz86fPy49/u5NDDhLfFA==", + "node_modules/@fluentui/react-divider": { + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.4.4.tgz", + "integrity": "sha512-Hg61v5YSh02H/fQJdfkzpqkrrupXIdzfbnRczCsjl5r9W2sqlO0STC100/SCmxtLoZN5208tM268NIPGfQLArw==", "license": "MIT", "dependencies": { - "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-motion": "^9.8.0", - "@fluentui/react-motion-components-preview": "^0.6.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1632,16 +1522,20 @@ "react-dom": ">=16.14.0 <19.0.0" } }, - "node_modules/@fluentui/react-divider": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.3.0.tgz", - "integrity": "sha512-8MvWlNcYQBIpIH8d90PRLYvqTA53t0Folv1xf2isC+YWeTm5J1siZtPRiZ9+K0uqI9Y+RD4fnWN8HfMeyOAjlw==", + "node_modules/@fluentui/react-drawer": { + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.10.0.tgz", + "integrity": "sha512-yoTJGoH6jgL2/Nu3wfJptbMZdGnHhUh4cOKESTiiSjCmVgmr56gGFzMjAICek1YLtrnxGBEAJngkOpyQFNHQtw==", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-dialog": "^9.15.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-motion": "^9.10.3", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1653,18 +1547,18 @@ } }, "node_modules/@fluentui/react-field": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.3.1.tgz", - "integrity": "sha512-9bzicAbR5+AtboowO6akbJsoMWDGUtbGenQT81mXt7HGg6RP86gpodgcr/4f1OG1w5VtrfoA/aoNExP/XzUeGg==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.4.4.tgz", + "integrity": "sha512-JtW3faTdKIE/d/mum9ZDkiC6vyip7h5rLa7zhIQ/Eek0JR2vHZwta8BODxY0Mwvga/xTK9aC3fNo/FcXSoL3Rg==", "license": "MIT", "dependencies": { - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-label": "^9.2.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-label": "^9.3.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1676,9 +1570,9 @@ } }, "node_modules/@fluentui/react-icons": { - "version": "2.0.302", - "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.302.tgz", - "integrity": "sha512-NK8w51dvucc6bu9oNoFZTWhXVelZ93JKnQbUH4Po344NJiBnzblv5ey4Vxz2SJj7T2t3oYBE+kb/ixTxwbxlaQ==", + "version": "2.0.308", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.308.tgz", + "integrity": "sha512-T8cUCHNNUEzs2WUkPdW7DQznNLdRzoSCVYzVn/niuY+ucxk5E666oMF6OfjlhpePw4WQdyqpmW/rTjSBw5wvvA==", "license": "MIT", "dependencies": { "@griffel/react": "^1.0.0", @@ -1689,15 +1583,15 @@ } }, "node_modules/@fluentui/react-image": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.2.0.tgz", - "integrity": "sha512-vP26rQDNx5LevbEKbf6dLjTx4uOZWIopjx6HQYSLk8axGWmjXe21t6BXRa9iTiPfibwJmWwzXvqGHxYR/as/wA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.3.4.tgz", + "integrity": "sha512-wtRE7D+1Td9Ha5asRxDuUCIGfx75ilIWgZDws2MQoZrVo05iSAf3F+Ylv+MuiQ2p8N46n8gGyUBNmyFwfWUfKA==", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1732,19 +1626,19 @@ } }, "node_modules/@fluentui/react-infolabel": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.3.1.tgz", - "integrity": "sha512-fL2J3PJy6ylPQrFFwAJgFoACxRk5d/PtzjL7JlmM1OCaUmUD2FuUovDYpubw9r36OemVOHTB/oXhpitlS3BoPQ==", + "version": "9.4.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.4.5.tgz", + "integrity": "sha512-sjUPSt1VeBkvHIn+Iq3LL+KXwrzLGANkR2MC80+OJNn59tk3jVFkcnlPxWYWnOD/Zlpl6SqIlKnzrVQGfIxxvA==", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-label": "^9.2.0", - "@fluentui/react-popover": "^9.11.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-label": "^9.3.4", + "@fluentui/react-popover": "^9.12.5", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1756,16 +1650,16 @@ } }, "node_modules/@fluentui/react-input": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.6.1.tgz", - "integrity": "sha512-IMwJxKjZYznlKFrZ6MoKpFXJxfGoJBJux4hDZzqDWyDafDSvjmTpiiutJbQmMRQpxQ4pPuaHBwcSScfExAf69g==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.7.4.tgz", + "integrity": "sha512-ZNhM5xKckA39O3g6LjwoZCqy8kopFQ1ujfwxl0D60fEDMBwUYoK2NR1Zr/pEF9ItuhKlIN9fs1F/Hqay7fnYDw==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1777,12 +1671,12 @@ } }, "node_modules/@fluentui/react-jsx-runtime": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.1.0.tgz", - "integrity": "sha512-HB4+1ofzmweSWrFPZeoeepzNNHu54jplCfPLlppBoHx1MZ11RR9w2uIsLjfSDrEPIZnXbQxVBItvDh9ZrU9new==", + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.1.6.tgz", + "integrity": "sha512-ClaksavUB9CPRPuMKxtsjVCg+N95jMt3Oi5RBGY4dAMxwaERpweQPv5CCuZzOq4Ybp4FpAXwK1jGNZzXizvfaA==", "license": "MIT", "dependencies": { - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-utilities": "^9.24.0", "@swc/helpers": "^0.5.1", "react-is": "^17.0.2" }, @@ -1792,15 +1686,15 @@ } }, "node_modules/@fluentui/react-label": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.2.0.tgz", - "integrity": "sha512-WDaBR9AmdPvJ0vXN9WicOlHFhI6BKgQXULl0YjMXuL51tl37txyvY2crv+YNeVsfykI18h6LOPxltPeEdAsxag==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.3.4.tgz", + "integrity": "sha512-oBdN3J5qFuiS57eCk+rXEYg+zt/7Mgt7SqxQlJzkU8uzlj5J5B+IjITlADOEYjuG0QDzhNA4/et2AX8c8kA55Q==", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1812,17 +1706,17 @@ } }, "node_modules/@fluentui/react-link": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.5.0.tgz", - "integrity": "sha512-bdEFARlbnTyzrKHKv7wvLMRua7/gUX1dOzBG+1tfmJFuFkE2gz7rxABBVdlaI1PHsgAbGnzQnSzl6C5DOPgqcA==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.6.4.tgz", + "integrity": "sha512-jmn/lkDt31bE8ZMgPQ9ZCeUeHJ7fL28HelOj8Mod9lhTfykyFESzWjd3oJQ0FSKta5I1oqwrBcxa4dIuDM2sfw==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1834,19 +1728,19 @@ } }, "node_modules/@fluentui/react-list": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-list/-/react-list-9.2.1.tgz", - "integrity": "sha512-UGRD+oBNtSRA+GH7n3qC07AatNvRLBQwSCoaza9ElYWsh4eWQzbp/zkurLWIM0PrAUd4JHuMswHARRBlJeY5gg==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-list/-/react-list-9.5.0.tgz", + "integrity": "sha512-iJIq5DNxRDog2AFror7d/7q7mzTcVnjejfF4ZhpIZW0hYOzpeVsZvCWilvg96ItvXgNApM3F369ZLLs1Q3uUIQ==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-checkbox": "^9.4.1", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-checkbox": "^9.5.4", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1858,22 +1752,22 @@ } }, "node_modules/@fluentui/react-menu": { - "version": "9.17.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.17.1.tgz", - "integrity": "sha512-aygFQRa6Zt8sZ6aBnR+OiNaFOmykg+X5BTPBiu2m6IlJs1Z42S2AuSj8OuBUjrFQ3LnxT579AHDZuTXBngCsEQ==", + "version": "9.19.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.19.5.tgz", + "integrity": "sha512-+tvO4m8DB0NBPnFedcpCvmNJVmC/6VQd2Gzn8VIqJOBVnm1xRQ85YjH7d8CK1FKdW26JhYAAj8pVIh8k+mLseA==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-positioning": "^9.18.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-positioning": "^9.20.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1885,18 +1779,18 @@ } }, "node_modules/@fluentui/react-message-bar": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.5.0.tgz", - "integrity": "sha512-rsJUrXQWazdQ8gUX+l4XzToA8BMOJ+8t6WjXYr48Ztp7E9oROKaralavF78yihwY3t1ceacSbKa4bQLNqONlDw==", + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.6.5.tgz", + "integrity": "sha512-YpCaYxN4Y0sFalk1GZ1L4MXSGLepvyON9uW1PVeWS89XQlWGPCSSEhFTUjWrQJar2wsJ8kv/LKreQb87mCYolg==", "license": "MIT", "dependencies": { - "@fluentui/react-button": "^9.5.0", + "@fluentui/react-button": "^9.6.5", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-link": "^9.5.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-link": "^9.6.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1", "react-transition-group": "^4.4.1" @@ -1909,13 +1803,13 @@ } }, "node_modules/@fluentui/react-motion": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-motion/-/react-motion-9.8.0.tgz", - "integrity": "sha512-TTwJV4iw7LHesPNtQpPmEb77YplC89Vh2+ru2vWS+f5YJbmduN4V/WH/ViakHjRGj/m03jRaQruTpg3rKGUCZw==", + "version": "9.10.3", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion/-/react-motion-9.10.3.tgz", + "integrity": "sha512-0UZyBSY73wP+p2s8FQsi4XdBCuGzjZ5MXy/2oohqX3yAb8t+F7e1ID0fJym9pnwwYkGeugZUlkWfyWgFPuSQag==", "license": "MIT", "dependencies": { - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-utilities": "^9.24.0", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -1926,9 +1820,9 @@ } }, "node_modules/@fluentui/react-motion-components-preview": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.6.0.tgz", - "integrity": "sha512-9PBaI25VGIuVKYE8Q4gew4/tsFmsOD4F1ZzHdEVkUS984pCZjC3LD5+6wrxpoJajDGk4cpWRRGl8x3DcO5CgHQ==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.9.0.tgz", + "integrity": "sha512-MkzDBtuZzFCW9RC7zW9e7r8AdcocpGigMQpL6gi9OYYEUDiIPSjTsitok9W0ZZ7H4gBy+p7MjG/we5JcsBCnpQ==", "license": "MIT", "dependencies": { "@fluentui/react-motion": "*", @@ -1942,47 +1836,24 @@ } }, "node_modules/@fluentui/react-nav": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-nav/-/react-nav-9.1.1.tgz", - "integrity": "sha512-kn+5KVDCoY/xPrpEegJv9SEVofqLOPLDWk2C5YBR0zZItzZ7cHfNxABsZ3fD0RM15ro5BaaHm6mfuDxERHluHA==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-nav/-/react-nav-9.3.5.tgz", + "integrity": "sha512-SumdUakSW1XWmzJG7OsiNuJDAhxHWa+uNvZ/rURJTFGkwSt+a1Fi0UL1uutyMtK1U5rCBRMtrf79r3M3+DURJw==", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-button": "^9.5.0", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-divider": "^9.3.0", - "@fluentui/react-drawer": "^9.8.1", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-button": "^9.6.5", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-divider": "^9.4.4", + "@fluentui/react-drawer": "^9.10.0", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-tooltip": "^9.7.1", - "@fluentui/react-utilities": "^9.21.0", - "@griffel/react": "^1.5.22", - "@swc/helpers": "^0.5.1" - }, - "peerDependencies": { - "@types/react": ">=16.14.0 <19.0.0", - "@types/react-dom": ">=16.9.0 <19.0.0", - "react": ">=16.14.0 <19.0.0", - "react-dom": ">=16.14.0 <19.0.0" - } - }, - "node_modules/@fluentui/react-nav/node_modules/@fluentui/react-drawer": { - "version": "9.8.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.8.1.tgz", - "integrity": "sha512-VjzG0qAXN7eXiBbFzM7YHpNes05YIdY3WHJD6V2FheHvmthzhw8GFqDnRHsZ581Wb9uB9xqi+WJ69vNJ9tS48Q==", - "license": "MIT", - "dependencies": { - "@fluentui/react-dialog": "^9.13.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-motion": "^9.8.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-motion": "^9.10.3", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-tooltip": "^9.8.4", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -1994,15 +1865,15 @@ } }, "node_modules/@fluentui/react-overflow": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.4.1.tgz", - "integrity": "sha512-qToEgEuyBWN2Te+9gg56fib/jCDwi3gBJhvZQSL8Ywgg3nNhmyAnOfGEdaMHrVL4DpFaNEOzxoC2C9vrzCx5bQ==", + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.5.5.tgz", + "integrity": "sha512-WbG0DMJ5B7hOIYncmXjG1odS37mlldPpqm4WXpDv2IMIYzzlcI8JDk0KimrAb2/FgLrRm3vWbxZ1hyb5YjImrg==", "license": "MIT", "dependencies": { "@fluentui/priority-overflow": "^9.1.15", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2014,17 +1885,17 @@ } }, "node_modules/@fluentui/react-persona": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.4.1.tgz", - "integrity": "sha512-+1LLEfSEsZqcYLKt80BPT7hPXwbP49SiOb5PSHvOM58HtruWtD+rx7xLFVcR9BnlJK/oZkRjisfQlAM3zuZ3Yw==", + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.5.5.tgz", + "integrity": "sha512-s//UCtV+Vf+/ghY3+InWph1mLOOG3NxhoRzttXDSfinzLXgDzf6PUPd+FbntK8eu6RyOllnquydnLTkDLt/k/g==", "license": "MIT", "dependencies": { - "@fluentui/react-avatar": "^9.8.1", - "@fluentui/react-badge": "^9.3.0", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-avatar": "^9.9.5", + "@fluentui/react-badge": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2036,21 +1907,21 @@ } }, "node_modules/@fluentui/react-popover": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.11.1.tgz", - "integrity": "sha512-f+/K+8zHAlrUR16NSEtZ4rYArPtm+PpEuC9qd7+PjrlI/GytZHqVlNA8X4ddHWQy+fJoqTSA6cbB+SEYK8/yPw==", + "version": "9.12.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.12.5.tgz", + "integrity": "sha512-GzIkJoyzRmgz8UgVq2xhqii/trIAMLpLYbr3XrxukrkDg837OZKFcBbSbqTUSNVZ6ra4RrlGMaF4yhWHBTSs1A==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-positioning": "^9.18.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-positioning": "^9.20.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2062,14 +1933,14 @@ } }, "node_modules/@fluentui/react-portal": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.6.0.tgz", - "integrity": "sha512-FiA3eM/1Um/3HZvfaGisdL7pLV4idWzlmDUIFBUOlzXsy57mIY9IwV5nDHYiJdEMkW0UstRVJB4oRaHoHGSqUg==", + "version": "9.8.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.8.1.tgz", + "integrity": "sha512-PjcKGNpphryhHBtlObbBVNrsasPt6QCbTyLYfmUKR92+XQI0U92AV9fHS7sArXGP3HrXjzUDvf+rLnecRMQmcA==", "license": "MIT", "dependencies": { - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2081,16 +1952,16 @@ } }, "node_modules/@fluentui/react-positioning": { - "version": "9.18.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.18.1.tgz", - "integrity": "sha512-+ueJus7IaezMAEDrlo3G/ihd+8Voa1W4dWrswH7Jknulggp8Mfaz1wMdZq8GvMuBnifMLJ33M9svsrJJahscPw==", + "version": "9.20.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.20.4.tgz", + "integrity": "sha512-MyldPBLO+hX0+qI2kfRZRI1hdSihgDKqpdqkl6O25PVce2SaGvvDAK72GDNOyoAApnXlVOFIEAyLSWzxjTGDbw==", "license": "MIT", "dependencies": { - "@floating-ui/devtools": "0.2.1", + "@floating-ui/devtools": "^0.2.3", "@floating-ui/dom": "^1.6.12", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1", "use-sync-external-store": "^1.2.0" @@ -2103,16 +1974,16 @@ } }, "node_modules/@fluentui/react-progress": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.3.1.tgz", - "integrity": "sha512-2+jMPtuANnU7mUVEyUhhLh2LJmZNHrH4sin5rjSlsipr3ifhCoFUOoOloHw+cuVFzHeQNxIV9AuzOODii6cU3g==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.4.4.tgz", + "integrity": "sha512-53oBCjgnqKLhX3amF8UczzBajOn1iQ1li4e14IIo+pmocI6kqohUWEBX6FUyor9+gSoty47pmS1T8izxyqnaCA==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2124,17 +1995,17 @@ } }, "node_modules/@fluentui/react-provider": { - "version": "9.21.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.21.0.tgz", - "integrity": "sha512-mADFjeZKN5e6AJJ45Nc99yDMmvzDPZea7G0PznByC4H/+JuZO3oExTve2SYSmj4KECyjv3wQVlMe7os9sCLZ6w==", + "version": "9.22.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.22.4.tgz", + "integrity": "sha512-GhNGnFtNue7ZDxZjln4NtZMon0WNgaVBwEeqk2f5v6yzaGQN6Qm6/Ke/oCVTv++weimk2Sxysy2iN+/fMG3w0Q==", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/core": "^1.16.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" @@ -2147,18 +2018,18 @@ } }, "node_modules/@fluentui/react-radio": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.4.1.tgz", - "integrity": "sha512-uQ+BeJeESBpC+MOC1coeiUlLVshpz2fjme3SKPuGDZv1x919Mh2e8OG5R1EcNGLJBMSVrU/LT8sqAV9WJ4k2cQ==", - "license": "MIT", - "dependencies": { - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-label": "^9.2.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.5.4.tgz", + "integrity": "sha512-wgqNgEMUbDmiSSNG8rtYYLVmkfABZyotTGAlyUMAsE4mw4wlcsLEFhVL2LNckH4a4DR/jeJb5McatgdpX7T4+Q==", + "license": "MIT", + "dependencies": { + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-label": "^9.3.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2170,17 +2041,17 @@ } }, "node_modules/@fluentui/react-rating": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-rating/-/react-rating-9.2.0.tgz", - "integrity": "sha512-GjEE6XmxDc8zTiQWZmiRJgXqKzreREQRUOimuBrG4exxKcoXj11Ah+oOrLJ/z/KmPyu0JGk5yHJ+VMuJeJh6gw==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-rating/-/react-rating-9.3.4.tgz", + "integrity": "sha512-Nq1dp7tVxTPJ8arqPaQKW9Apw7clkqVH6zZc/9ssSqEQO4ap4pWZPY0omSkxwdk15jH0AKzXMGTN5eT9MfK8Kw==", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2192,17 +2063,17 @@ } }, "node_modules/@fluentui/react-search": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-search/-/react-search-9.2.1.tgz", - "integrity": "sha512-tFfo72YnBLK4nIIpaL8IE0Qu1hHGOjbbl2TxM6NN9qddp0s+5WeUHtpE1auyMeY4s1UQNbZbtjmsBpzicCAlaQ==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-search/-/react-search-9.3.4.tgz", + "integrity": "sha512-l3JK18E+VQ+zZ0u9Id+xr3b1+KS8bWRVqbhU5Cm/BdtipW0pr/uzG8i5IH64pPLu9S0hfI4ROCQ2miZ5bBmO4g==", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-input": "^9.6.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-input": "^9.7.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2214,17 +2085,17 @@ } }, "node_modules/@fluentui/react-select": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.3.1.tgz", - "integrity": "sha512-BvylsBcUzH8t/miTo/kesuv6GgTW6AiipFkTFsoeKqXS4kWYOZx3+ufVytdU9Pcowr0WrSBy6s/206JCQR3nVg==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.4.4.tgz", + "integrity": "sha512-NFAaZ1kMrMLNOqKlxkgIW66rO8RCNG3PRwbPBvHkMawupoFSiHag5r7YLxZsn1OX8HFnXz9wp083ZjWXHvEwWA==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", + "@fluentui/react-field": "^9.4.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2236,12 +2107,12 @@ } }, "node_modules/@fluentui/react-shared-contexts": { - "version": "9.23.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.23.1.tgz", - "integrity": "sha512-mP+7talxLz7n0G36o7Asdvst+JPzUbqbnoMKUWRVB5YwzlOXumEgaQDgL1BkRUJYaDGOjIiSTUjHOEkBt7iSdg==", + "version": "9.25.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.25.0.tgz", + "integrity": "sha512-uFWi93L5ZjZACx5VA4+gbWgg6l/on3ultJpXTyFYFuox0paJbqENsPf383GKZW7UnUs08Kqry5CFC36VfqDdSg==", "license": "MIT", "dependencies": { - "@fluentui/react-theme": "^9.1.24", + "@fluentui/react-theme": "^9.2.0", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -2250,16 +2121,16 @@ } }, "node_modules/@fluentui/react-skeleton": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.3.1.tgz", - "integrity": "sha512-gI05SgPkrACHH7dy2ZM5had1/Px99Wpvsxl+gzBCzloqeNlm0Eh1H/TH5UdFOm+0IA/Lit/8crwqSNRmHL/Viw==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.4.4.tgz", + "integrity": "sha512-keXTUdweqPMffECCLoc2Fu35xxpLUNh3opGy4/ShT73YVTQgLyRTJMKv5v+y2TzujWP9T/THm+HHxe56eQBrVQ==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2271,17 +2142,17 @@ } }, "node_modules/@fluentui/react-slider": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.4.1.tgz", - "integrity": "sha512-pJeh2gRXV4/uDbT2HAcWmp7zxq3Bwr48/LHzsPngwKP6W8Pgw7NysMZimJVs3B5nL4KXZyyH/ArDy6IV7pl/Aw==", + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.5.4.tgz", + "integrity": "sha512-AX6t49OMF/OWDN6M+gsBUu5ZAuhswLdvrnuRJY+jMHWSMitTK2DBgruNUKhpA1K5Kl0ZqFHlU8eTMti8FT6Nog==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2293,18 +2164,18 @@ } }, "node_modules/@fluentui/react-spinbutton": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.4.1.tgz", - "integrity": "sha512-dUj4XEocE5Uy0TWFxFNVGyRZpNJCHNl/VNWwJcDPNf6Jb5ThqGcXZ4IgWO00GoucwTkUzIHE37SSBGatL3ANsA==", + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.5.4.tgz", + "integrity": "sha512-MiNih2+ds5acPXNLYufvD9pnD6z2pZH0OHATrCh6MngAdbSTC5vR2+lP9qvBj02zQ/L4nZEcuaLbd4BrP7KUpg==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-field": "^9.3.1", + "@fluentui/react-field": "^9.4.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2316,16 +2187,16 @@ } }, "node_modules/@fluentui/react-spinner": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.6.0.tgz", - "integrity": "sha512-yRUozOphh92DMM/hZLp2aF12vWGpz70M7ya//E0PVhwXMD2zJf7EvK/HvgdtMNoiSkM9nYrEoe4HuEialn2WQQ==", + "version": "9.7.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.7.4.tgz", + "integrity": "sha512-d4HTD4TlvM4PN+J5iWOrGqcfOyoPbX+KEQbUexX/4ZBNcGPsAbHtLH4IHoQTZIYUKRurLZH1dnTgyeTjraR2HQ==", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-label": "^9.2.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-label": "^9.3.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2337,19 +2208,19 @@ } }, "node_modules/@fluentui/react-swatch-picker": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-swatch-picker/-/react-swatch-picker-9.3.1.tgz", - "integrity": "sha512-W7Dz9pF39KdNdYLFR6ySa13et/i+5LLkY6HrGg9k3LxtAYwCeooy++4FBYpWE87i+FcuiAGKmzhy6vHM5i2TBA==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-swatch-picker/-/react-swatch-picker-9.4.4.tgz", + "integrity": "sha512-U0xZRd9v4C/fwlx7ux4ufY2OWCnLzClqc97r+Roeg+5FCF3ACEwocwQoA/Md/uQxqVjeIMTyxW20Ozlk4rnLYQ==", "license": "MIT", "dependencies": { - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-field": "^9.3.1", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-field": "^9.4.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2361,19 +2232,19 @@ } }, "node_modules/@fluentui/react-switch": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.3.1.tgz", - "integrity": "sha512-QxmTGQQdUWpfGe40RafooeHeM8evAz6dItDsEEenu4h8KbrD0fztBjDG51fjuAPsrbYzoPS1o684+dD8pl2tNw==", + "version": "9.4.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.4.4.tgz", + "integrity": "sha512-9DyAGW5L/cmxp6R9HNmP4SoSlzdf9oO7Z3Hbu5DoMHKTvL3hU86K84MeU1fNaDbHEkdgdVFMYt5QFbzoW/lkqw==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", + "@fluentui/react-field": "^9.4.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-label": "^9.2.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-label": "^9.3.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2385,23 +2256,23 @@ } }, "node_modules/@fluentui/react-table": { - "version": "9.17.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.17.1.tgz", - "integrity": "sha512-iDaX/wK4UmxYoqUPNK84553UTiYBB3YwPPjIkpxoxlv+RnjnPDshmDRT4KzCDNI2NvuhinwaKtj+b8DvMnFwHA==", + "version": "9.18.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.18.5.tgz", + "integrity": "sha512-JQy7HiHiMkfi0H8u/cKui8mhRc3ESuClGSS2IRoGyCDPILRuwf1OW6h6uPMTf5DYJV5OnEwxQTM8zAjPTmZH1g==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-avatar": "^9.8.1", - "@fluentui/react-checkbox": "^9.4.1", - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-avatar": "^9.9.5", + "@fluentui/react-checkbox": "^9.5.4", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-radio": "^9.4.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-radio": "^9.5.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2413,17 +2284,17 @@ } }, "node_modules/@fluentui/react-tabs": { - "version": "9.8.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.8.0.tgz", - "integrity": "sha512-0dwF8v2rSRd7c3XV+LiHlf4eetXf79S2iBmLUZKmi+BQHWZv9NhmDLOw6DE8yidcHvlKlvXcUz+UNmVLXdmsCw==", + "version": "9.10.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.10.0.tgz", + "integrity": "sha512-fFHAXmOwz+ESt23CKgicvu76FzVYywcCj+/nL8xjMtulEnoNrKC1SkLwScTgeJgo+WQw2RchyG1fdFppPVz+zA==", "license": "MIT", "dependencies": { - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2435,14 +2306,14 @@ } }, "node_modules/@fluentui/react-tabster": { - "version": "9.25.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.25.0.tgz", - "integrity": "sha512-V0f0lWt/PZZ0ZDTz47qdvf4vQ5v0W2EZwhZlE2DTSiQ2U5hLAZhXKwCoM6T0nN+mviplQshNWBenbI6HS1RKgg==", + "version": "9.26.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.26.4.tgz", + "integrity": "sha512-ri/h4MHdSdTPn40isPZw1tOnB4W+wLj0EtJWDdKc49vDX8NXTmULLBDodHDsqauVJpKMw3Jw69Ccuf09S+qhTA==", "license": "MIT", "dependencies": { - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1", "keyborg": "^2.6.0", @@ -2455,16 +2326,98 @@ "react-dom": ">=16.14.0 <19.0.0" } }, + "node_modules/@fluentui/react-tag-picker": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-tag-picker/-/react-tag-picker-9.7.5.tgz", + "integrity": "sha512-0FlRcHhk08q1fR6YkUNShqSPT+Cq9LPsTVU2nlwk0piVY2BxTbCYD+lK+qjJmJHIXUtOA1naQESRdQMmrStfYA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-combobox": "^9.16.5", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-positioning": "^9.20.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-tags": "^9.7.5", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tags": { + "version": "9.7.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.7.5.tgz", + "integrity": "sha512-9rJv6bHzMsEvmWJFIUwq1bgLZ7D1XZ556fOtPl9P7JU2i6gCYzkXCakHm9faUJnNw2CcKq0aw38sGJoHR7wNuA==", + "license": "MIT", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.8", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-avatar": "^9.9.5", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover": { + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-teaching-popover/-/react-teaching-popover-9.6.5.tgz", + "integrity": "sha512-fNSwEXRPDa5qRjgEI8vvlki279/hhCWeQyYFyJ4D4pRga8u3CGa6RI33GuUsxHO2ROOgMRFh2JJIYlG/+GMhjQ==", + "license": "MIT", + "dependencies": { + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-button": "^9.6.5", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-popover": "^9.12.5", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, "node_modules/@fluentui/react-text": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.5.0.tgz", - "integrity": "sha512-mT//jeZDafU2zEBkSsRjLWtwJ6jyj/f5DPRZQ7/sA9yeQ4YDoXoJ2+x5IoG4VX4tkK1CRvmR4LA/V8JvrWjVyg==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.6.4.tgz", + "integrity": "sha512-plHq9chCXcV9wtwNUtQYJSCTMJyEtMKHFj9s54ZS6GZOIxm/SIqsSz5ZAR25mgdn4mlyuMS+Ac3nBR83T+zVDw==", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2476,16 +2429,16 @@ } }, "node_modules/@fluentui/react-textarea": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.5.1.tgz", - "integrity": "sha512-wGl2rHdv1ZONOSyIjjjbTI/SDRKV89rWF6yVS2qcCI5TFC5SoxadqG+u/9Fuy3kpv69WwRU8Op3mDSz+GYFa/A==", + "version": "9.6.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.6.4.tgz", + "integrity": "sha512-Gb6XkGNAiPE19cBfIkJVph3hKxubNrh5/idRQVDpQapjlRC2d8RmnNtUIlLwkiWtIdFvis0lxZuATQlDTQlnBA==", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.3.1", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-field": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2497,32 +2450,32 @@ } }, "node_modules/@fluentui/react-theme": { - "version": "9.1.24", - "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.24.tgz", - "integrity": "sha512-OhVKYD7CMYHxzJEn4PtIszledj8hbQJNWBMfIZsp4Sytdp9vCi0txIQUx4BhS1WqtQPhNGCF16eW9Q3NRrnIrQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.2.0.tgz", + "integrity": "sha512-Q0zp/MY1m5RjlkcwMcjn/PQRT2T+q3bgxuxWbhgaD07V+tLzBhGROvuqbsdg4YWF/IK21zPfLhmGyifhEu0DnQ==", "license": "MIT", "dependencies": { - "@fluentui/tokens": "1.0.0-alpha.21", + "@fluentui/tokens": "1.0.0-alpha.22", "@swc/helpers": "^0.5.1" } }, "node_modules/@fluentui/react-toast": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.5.0.tgz", - "integrity": "sha512-TPgNNxfP5X80Pl/H7jVgreGKfDdEkN/L6G1rnjM18emsIw0DYB+B46JoBwmrPCvISZJNnLstSftwwDSqQEO2hg==", + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.7.0.tgz", + "integrity": "sha512-8GjhlUhKheDOEJudFCVCU9zFnXO66cAfn7xeMeIda5ZwdknD9Qh05bFLK68MRfBj9KpzfJC7tX84ztLDihVqzg==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", + "@fluentui/react-aria": "^9.16.4", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-motion": "^9.8.0", - "@fluentui/react-motion-components-preview": "^0.6.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-motion": "^9.10.3", + "@fluentui/react-motion-components-preview": "^0.9.0", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2534,20 +2487,20 @@ } }, "node_modules/@fluentui/react-toolbar": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.5.1.tgz", - "integrity": "sha512-8lI8lrRMdm3q9K31iKrOXbC+65OnSi+GtO06FjcKd413x0fBAYbWweRciAh3IyIAiU38RdjIvLKiIs92TuqUpg==", - "license": "MIT", - "dependencies": { - "@fluentui/react-button": "^9.5.0", - "@fluentui/react-context-selector": "^9.2.0", - "@fluentui/react-divider": "^9.3.0", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-radio": "^9.4.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "version": "9.6.5", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.6.5.tgz", + "integrity": "sha512-eHnZb2+/2AL0ZWO9dgm4IirXBgzFTCVEDT2oXMXNG49IbbZOrPo+MX+POb4gduKUdOE7STJvrgw79ePs+Q94hA==", + "license": "MIT", + "dependencies": { + "@fluentui/react-button": "^9.6.5", + "@fluentui/react-context-selector": "^9.2.6", + "@fluentui/react-divider": "^9.4.4", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-radio": "^9.5.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2559,19 +2512,19 @@ } }, "node_modules/@fluentui/react-tooltip": { - "version": "9.7.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.7.1.tgz", - "integrity": "sha512-LiIQDOGEsGeuAbiQItOL/OvSiX9gY5wKgUCduv1cSqQ2J/f3FbsPudBlQJs8UhukdT1jTqF7sjoNel6rMg/rNQ==", + "version": "9.8.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.8.4.tgz", + "integrity": "sha512-Yb8kW37CmK2CI5zilYYnvVjeXKyH1S8Fdi5lXmL6sm48Vf/Ad5s8WKYGzTRq7faLN7oR2R53Z+t8g7EEGfhO2w==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-portal": "^9.6.0", - "@fluentui/react-positioning": "^9.18.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-portal": "^9.8.1", + "@fluentui/react-positioning": "^9.20.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2583,26 +2536,26 @@ } }, "node_modules/@fluentui/react-tree": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.11.1.tgz", - "integrity": "sha512-ORRyUoDZzo0GOmiZKwnFlompCjVDi++5tBzf0o/8YQ0xOIlyuCp12oK0UI0AKATXC3lldTupmk0XSorbI4z4qg==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.13.0.tgz", + "integrity": "sha512-UJKiZyqtqE1c2ICtUSDuTVe1bZb+i5CVOZvQrgjNiSolRKAFrLEOk7G+wOjq6X4OPwiZRp+rpkHLr6KTJ3LFsg==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.15.0", - "@fluentui/react-avatar": "^9.8.1", - "@fluentui/react-button": "^9.5.0", - "@fluentui/react-checkbox": "^9.4.1", - "@fluentui/react-context-selector": "^9.2.0", + "@fluentui/react-aria": "^9.16.4", + "@fluentui/react-avatar": "^9.9.5", + "@fluentui/react-button": "^9.6.5", + "@fluentui/react-checkbox": "^9.5.4", + "@fluentui/react-context-selector": "^9.2.6", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.1.0", - "@fluentui/react-motion": "^9.8.0", - "@fluentui/react-motion-components-preview": "^0.6.0", - "@fluentui/react-radio": "^9.4.1", - "@fluentui/react-shared-contexts": "^9.23.1", - "@fluentui/react-tabster": "^9.25.0", - "@fluentui/react-theme": "^9.1.24", - "@fluentui/react-utilities": "^9.21.0", + "@fluentui/react-jsx-runtime": "^9.1.6", + "@fluentui/react-motion": "^9.10.3", + "@fluentui/react-motion-components-preview": "^0.9.0", + "@fluentui/react-radio": "^9.5.4", + "@fluentui/react-shared-contexts": "^9.25.0", + "@fluentui/react-tabster": "^9.26.4", + "@fluentui/react-theme": "^9.2.0", + "@fluentui/react-utilities": "^9.24.0", "@griffel/react": "^1.5.22", "@swc/helpers": "^0.5.1" }, @@ -2614,13 +2567,13 @@ } }, "node_modules/@fluentui/react-utilities": { - "version": "9.21.0", - "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.21.0.tgz", - "integrity": "sha512-xViS1WwKIdPza+syMsfh1i3hNgssWgLtbevEeGb6DS/q13UKXaw9P/vezPUs6kSolnSD/juWZGP6u8ytkI1W7g==", + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.24.0.tgz", + "integrity": "sha512-fIAEi62slg3YGe9nbUW4crD9KLx//eNWBVRuwEvhqJeqrbLL6dTWRAmRhmYOmzzySy+4gxHP7I/D7jl3BjeXpA==", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-shared-contexts": "^9.23.1", + "@fluentui/react-shared-contexts": "^9.25.0", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -2628,6 +2581,25 @@ "react": ">=16.14.0 <19.0.0" } }, + "node_modules/@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.102", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.102.tgz", + "integrity": "sha512-kt/kuAMTKTTY/00ToUlgUwUCty2HGj4Tnr+fxKRmr7Ziy5VWhi1YoNJ8vcgmxog5J90t4tS29LB0LP0KztQUVg==", + "license": "MIT", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.1.4", + "@fluentui/react-shared-contexts": "^9.24.1", + "@fluentui/react-utilities": "^9.23.1", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, "node_modules/@fluentui/set-version": { "version": "8.2.24", "resolved": "https://registry.npmjs.org/@fluentui/set-version/-/set-version-8.2.24.tgz", @@ -2638,9 +2610,9 @@ } }, "node_modules/@fluentui/tokens": { - "version": "1.0.0-alpha.21", - "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.21.tgz", - "integrity": "sha512-xQ1T56sNgDFGl+kJdIwhz67mHng8vcwO7Dvx5Uja4t+NRULQBgMcJ4reUo4FGF3TjufHj08pP0/OnKQgnOaSVg==", + "version": "1.0.0-alpha.22", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.22.tgz", + "integrity": "sha512-i9fgYyyCWFRdUi+vQwnV6hp7wpLGK4p09B+O/f2u71GBXzPuniubPYvrIJYtl444DD6shLjYToJhQ1S6XTFwLg==", "license": "MIT", "dependencies": { "@swc/helpers": "^0.5.1" @@ -2721,18 +2693,14 @@ "license": "BSD-3-Clause" }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -2745,27 +2713,17 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2819,16 +2777,16 @@ "license": "MIT" }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.11", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz", - "integrity": "sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==", + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz", - "integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.47.1.tgz", + "integrity": "sha512-lTahKRJip0knffA/GTNFJMrToD+CM+JJ+Qt5kjzBK/sFQ0EWqfKW3AYQSlZXN98tX0lx66083U9JYIMioMMK7g==", "cpu": [ "arm" ], @@ -2840,9 +2798,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz", - "integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.47.1.tgz", + "integrity": "sha512-uqxkb3RJLzlBbh/bbNQ4r7YpSZnjgMgyoEOY7Fy6GCbelkDSAzeiogxMG9TfLsBbqmGsdDObo3mzGqa8hps4MA==", "cpu": [ "arm64" ], @@ -2854,9 +2812,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz", - "integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.47.1.tgz", + "integrity": "sha512-tV6reObmxBDS4DDyLzTDIpymthNlxrLBGAoQx6m2a7eifSNEZdkXQl1PE4ZjCkEDPVgNXSzND/k9AQ3mC4IOEQ==", "cpu": [ "arm64" ], @@ -2868,9 +2826,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz", - "integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.47.1.tgz", + "integrity": "sha512-XuJRPTnMk1lwsSnS3vYyVMu4x/+WIw1MMSiqj5C4j3QOWsMzbJEK90zG+SWV1h0B1ABGCQ0UZUjti+TQK35uHQ==", "cpu": [ "x64" ], @@ -2882,9 +2840,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz", - "integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.47.1.tgz", + "integrity": "sha512-79BAm8Ag/tmJ5asCqgOXsb3WY28Rdd5Lxj8ONiQzWzy9LvWORd5qVuOnjlqiWWZJw+dWewEktZb5yiM1DLLaHw==", "cpu": [ "arm64" ], @@ -2896,9 +2854,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz", - "integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.47.1.tgz", + "integrity": "sha512-OQ2/ZDGzdOOlyfqBiip0ZX/jVFekzYrGtUsqAfLDbWy0jh1PUU18+jYp8UMpqhly5ltEqotc2miLngf9FPSWIA==", "cpu": [ "x64" ], @@ -2910,9 +2868,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz", - "integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.47.1.tgz", + "integrity": "sha512-HZZBXJL1udxlCVvoVadstgiU26seKkHbbAMLg7680gAcMnRNP9SAwTMVet02ANA94kXEI2VhBnXs4e5nf7KG2A==", "cpu": [ "arm" ], @@ -2924,9 +2882,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz", - "integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.47.1.tgz", + "integrity": "sha512-sZ5p2I9UA7T950JmuZ3pgdKA6+RTBr+0FpK427ExW0t7n+QwYOcmDTK/aRlzoBrWyTpJNlS3kacgSlSTUg6P/Q==", "cpu": [ "arm" ], @@ -2938,9 +2896,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz", - "integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.47.1.tgz", + "integrity": "sha512-3hBFoqPyU89Dyf1mQRXCdpc6qC6At3LV6jbbIOZd72jcx7xNk3aAp+EjzAtN6sDlmHFzsDJN5yeUySvorWeRXA==", "cpu": [ "arm64" ], @@ -2952,9 +2910,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz", - "integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.47.1.tgz", + "integrity": "sha512-49J4FnMHfGodJWPw73Ve+/hsPjZgcXQGkmqBGZFvltzBKRS+cvMiWNLadOMXKGnYRhs1ToTGM0sItKISoSGUNA==", "cpu": [ "arm64" ], @@ -2966,9 +2924,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz", - "integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.47.1.tgz", + "integrity": "sha512-4yYU8p7AneEpQkRX03pbpLmE21z5JNys16F1BZBZg5fP9rIlb0TkeQjn5du5w4agConCCEoYIG57sNxjryHEGg==", "cpu": [ "loong64" ], @@ -2979,10 +2937,10 @@ "linux" ] }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz", - "integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.47.1.tgz", + "integrity": "sha512-fAiq+J28l2YMWgC39jz/zPi2jqc0y3GSRo1yyxlBHt6UN0yYgnegHSRPa3pnHS5amT/efXQrm0ug5+aNEu9UuQ==", "cpu": [ "ppc64" ], @@ -2994,9 +2952,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz", - "integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.47.1.tgz", + "integrity": "sha512-daoT0PMENNdjVYYU9xec30Y2prb1AbEIbb64sqkcQcSaR0zYuKkoPuhIztfxuqN82KYCKKrj+tQe4Gi7OSm1ow==", "cpu": [ "riscv64" ], @@ -3008,9 +2966,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz", - "integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.47.1.tgz", + "integrity": "sha512-JNyXaAhWtdzfXu5pUcHAuNwGQKevR+6z/poYQKVW+pLaYOj9G1meYc57/1Xv2u4uTxfu9qEWmNTjv/H/EpAisw==", "cpu": [ "riscv64" ], @@ -3022,9 +2980,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz", - "integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.47.1.tgz", + "integrity": "sha512-U/CHbqKSwEQyZXjCpY43/GLYcTVKEXeRHw0rMBJP7fP3x6WpYG4LTJWR3ic6TeYKX6ZK7mrhltP4ppolyVhLVQ==", "cpu": [ "s390x" ], @@ -3049,9 +3007,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz", - "integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.47.1.tgz", + "integrity": "sha512-Ft+d/9DXs30BK7CHCTX11FtQGHUdpNDLJW0HHLign4lgMgBcPFN3NkdIXhC5r9iwsMwYreBBc4Rho5ieOmKNVQ==", "cpu": [ "x64" ], @@ -3063,9 +3021,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz", - "integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.47.1.tgz", + "integrity": "sha512-N9X5WqGYzZnjGAFsKSfYFtAShYjwOmFJoWbLg3dYixZOZqU7hdMq+/xyS14zKLhFhZDhP9VfkzQnsdk0ZDS9IA==", "cpu": [ "arm64" ], @@ -3077,9 +3035,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz", - "integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.47.1.tgz", + "integrity": "sha512-O+KcfeCORZADEY8oQJk4HK8wtEOCRE4MdOkb8qGZQNun3jzmj2nmhV/B/ZaaZOkPmJyvm/gW9n0gsB4eRa1eiQ==", "cpu": [ "ia32" ], @@ -3091,9 +3049,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz", - "integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.47.1.tgz", + "integrity": "sha512-CpKnYa8eHthJa3c+C38v/E+/KZyF1Jdh2Cz3DyKZqEWYgrM1IHFArXNWvBLPQCKUEsAqqKX27tTqVEFbDNUcOA==", "cpu": [ "x64" ], @@ -3114,18 +3072,18 @@ } }, "node_modules/@testing-library/dom": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", - "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", - "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", + "picocolors": "1.1.1", "pretty-format": "^27.0.2" }, "engines": { @@ -3133,17 +3091,16 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", - "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.8.0.tgz", + "integrity": "sha512-WgXcWzVM6idy5JaftTVC8Vs83NKRmGJz4Hqs4oyOuO2J4r/y79vvKZsb+CaGyCSEbUPI6OsewfPd0G1A0/TUZQ==", "license": "MIT", "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", - "chalk": "^3.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", + "picocolors": "^1.1.1", "redent": "^3.0.0" }, "engines": { @@ -3152,19 +3109,6 @@ "yarn": ">=1" } }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", @@ -3256,13 +3200,13 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", - "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/chai": { @@ -3348,9 +3292,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.0.tgz", - "integrity": "sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q==", + "version": "20.19.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.11.tgz", + "integrity": "sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==", "dev": true, "license": "MIT", "dependencies": { @@ -3598,16 +3542,16 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.5.2.tgz", - "integrity": "sha512-QNVT3/Lxx99nMQWJWF7K4N6apUEuT0KlZA3mx/mVaoGj3smm/8rc8ezz15J1pcbcjDK0V15rpHetVfya08r76Q==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.27.4", + "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.11", + "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, @@ -3615,7 +3559,7 @@ "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@vitest/expect": { @@ -3779,9 +3723,9 @@ } }, "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, "license": "MIT", "engines": { @@ -4036,13 +3980,13 @@ } }, "node_modules/axios": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", - "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, @@ -4094,9 +4038,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", - "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", + "version": "4.25.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz", + "integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==", "dev": true, "funding": [ { @@ -4114,8 +4058,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001718", - "electron-to-chromium": "^1.5.160", + "caniuse-lite": "^1.0.30001735", + "electron-to-chromium": "^1.5.204", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -4196,9 +4140,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001723", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz", - "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==", + "version": "1.0.30001736", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001736.tgz", + "integrity": "sha512-ImpN5gLEY8gWeqfLUyEF4b7mYWcYoR2Si1VhnrbM4JizRFmfGaAQ12PhNykq6nvI4XvKLrsp8Xde74D5phJOSw==", "dev": true, "funding": [ { @@ -4388,9 +4332,9 @@ } }, "node_modules/css-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.1.2.tgz", - "integrity": "sha512-WfUcL99xWDs7b3eZPoRszWVfbNo8ErCF15PTvVROjkShGlAfjIkG6hlfj/sl6/rfo5Q9x9ryJ3VqVnAZDA+gcw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.1.3.tgz", + "integrity": "sha512-gJMigczVZqYAk0hPVzx/M4Hm1D9QOtqkdQk9005TNzDIUGzo5cnHEDiKUT7jGPximL/oYb+LIitcHFQ4aKupxg==", "funding": [ { "type": "github", @@ -4410,9 +4354,9 @@ "license": "MIT" }, "node_modules/cssstyle": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.4.0.tgz", - "integrity": "sha512-W0Y2HOXlPkb2yaKrCVRjinYKciu/qSLEmK0K9mcfDei3zwlnHFEHAs/Du3cIRwPqY+J4JsiBzUjoHyc8RsJ03A==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", "dev": true, "license": "MIT", "dependencies": { @@ -4423,13 +4367,6 @@ "node": ">=18" } }, - "node_modules/cssstyle/node_modules/rrweb-cssom": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", - "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", - "dev": true, - "license": "MIT" - }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -4522,16 +4459,16 @@ } }, "node_modules/decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", "dev": true, "license": "MIT" }, "node_modules/decode-named-character-reference": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", - "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -4682,9 +4619,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.167", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.167.tgz", - "integrity": "sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==", + "version": "1.5.208", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.208.tgz", + "integrity": "sha512-ozZyibehoe7tOhNaf16lKmljVf+3npZcJIEbJRVftVsmAg5TeA1mGS9dVCZzOwr2xT7xK15V0p7+GZqSPgkuPg==", "dev": true, "license": "ISC" }, @@ -5136,22 +5073,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -5386,9 +5307,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -5600,13 +5521,19 @@ } }, "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globalthis": { @@ -6605,31 +6532,30 @@ } }, "node_modules/jsdom": { - "version": "24.1.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.3.tgz", - "integrity": "sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==", + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", "dev": true, "license": "MIT", "dependencies": { - "cssstyle": "^4.0.1", + "cssstyle": "^4.2.1", "data-urls": "^5.0.0", - "decimal.js": "^10.4.3", - "form-data": "^4.0.0", + "decimal.js": "^10.5.0", "html-encoding-sniffer": "^4.0.0", "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.5", + "https-proxy-agent": "^7.0.6", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.12", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.7.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.4", + "tough-cookie": "^5.1.1", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^14.0.0", + "whatwg-url": "^14.1.1", "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, @@ -6637,7 +6563,7 @@ "node": ">=18" }, "peerDependencies": { - "canvas": "^2.11.2" + "canvas": "^3.0.0" }, "peerDependenciesMeta": { "canvas": { @@ -6754,12 +6680,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -6816,13 +6736,13 @@ } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.18", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/markdown-table": { @@ -7825,9 +7745,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", "dev": true, "license": "MIT" }, @@ -8266,19 +8186,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, - "node_modules/psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, - "funding": { - "url": "https://github.com/sponsors/lupomontero" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -8289,13 +8196,6 @@ "node": ">=6" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true, - "license": "MIT" - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -8395,9 +8295,9 @@ } }, "node_modules/react-router": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.6.2.tgz", - "integrity": "sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.1.tgz", + "integrity": "sha512-5cy/M8DHcG51/KUIka1nfZ2QeylS4PJRs6TT8I4PF5axVsI5JUxp0hC0NZ/AEEj8Vw7xsEoD7L/6FY+zoYaOGA==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -8417,12 +8317,12 @@ } }, "node_modules/react-router-dom": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.2.tgz", - "integrity": "sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.8.1.tgz", + "integrity": "sha512-NkgBCF3sVgCiAWIlSt89GR2PLaksMpoo3HDCorpRfnCEfdtRPLiuTf+CNXvqZMI5SJLZCLpVCvcZrTdtGW64xQ==", "license": "MIT", "dependencies": { - "react-router": "7.6.2" + "react-router": "7.8.1" }, "engines": { "node": ">=20.0.0" @@ -8603,13 +8503,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "license": "MIT" - }, "node_modules/resolve": { "version": "2.0.0-next.5", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", @@ -8667,13 +8560,13 @@ } }, "node_modules/rollup": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz", - "integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.47.1.tgz", + "integrity": "sha512-iasGAQoZ5dWDzULEUX3jiW0oB1qyFOepSyDyoU6S/OhVlDIwj5knI5QBa5RRQ0sK7OE0v+8VIi2JuV+G+3tfNg==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -8683,33 +8576,33 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.43.0", - "@rollup/rollup-android-arm64": "4.43.0", - "@rollup/rollup-darwin-arm64": "4.43.0", - "@rollup/rollup-darwin-x64": "4.43.0", - "@rollup/rollup-freebsd-arm64": "4.43.0", - "@rollup/rollup-freebsd-x64": "4.43.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", - "@rollup/rollup-linux-arm-musleabihf": "4.43.0", - "@rollup/rollup-linux-arm64-gnu": "4.43.0", - "@rollup/rollup-linux-arm64-musl": "4.43.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-musl": "4.43.0", - "@rollup/rollup-linux-s390x-gnu": "4.43.0", - "@rollup/rollup-linux-x64-gnu": "4.43.0", - "@rollup/rollup-linux-x64-musl": "4.43.0", - "@rollup/rollup-win32-arm64-msvc": "4.43.0", - "@rollup/rollup-win32-ia32-msvc": "4.43.0", - "@rollup/rollup-win32-x64-msvc": "4.43.0", + "@rollup/rollup-android-arm-eabi": "4.47.1", + "@rollup/rollup-android-arm64": "4.47.1", + "@rollup/rollup-darwin-arm64": "4.47.1", + "@rollup/rollup-darwin-x64": "4.47.1", + "@rollup/rollup-freebsd-arm64": "4.47.1", + "@rollup/rollup-freebsd-x64": "4.47.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.47.1", + "@rollup/rollup-linux-arm-musleabihf": "4.47.1", + "@rollup/rollup-linux-arm64-gnu": "4.47.1", + "@rollup/rollup-linux-arm64-musl": "4.47.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.47.1", + "@rollup/rollup-linux-ppc64-gnu": "4.47.1", + "@rollup/rollup-linux-riscv64-gnu": "4.47.1", + "@rollup/rollup-linux-riscv64-musl": "4.47.1", + "@rollup/rollup-linux-s390x-gnu": "4.47.1", + "@rollup/rollup-linux-x64-gnu": "4.47.1", + "@rollup/rollup-linux-x64-musl": "4.47.1", + "@rollup/rollup-win32-arm64-msvc": "4.47.1", + "@rollup/rollup-win32-ia32-msvc": "4.47.1", + "@rollup/rollup-win32-x64-msvc": "4.47.1", "fsevents": "~2.3.2" } }, "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz", - "integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==", + "version": "4.47.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.47.1.tgz", + "integrity": "sha512-uTLEakjxOTElfeZIGWkC34u2auLHB1AYS6wBjPGI00bWdxdLcCzK5awjs25YXpqB9lS8S0vbO0t9ZcBeNibA7g==", "cpu": [ "x64" ], @@ -8720,17 +8613,10 @@ "linux" ] }, - "node_modules/rollup/node_modules/@types/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/rrweb-cssom": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", - "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true, "license": "MIT" }, @@ -9270,18 +9156,18 @@ "license": "MIT" }, "node_modules/style-to-js": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.16.tgz", - "integrity": "sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==", + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", "license": "MIT", "dependencies": { - "style-to-object": "1.0.8" + "style-to-object": "1.0.9" } }, "node_modules/style-to-object": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", - "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", "license": "MIT", "dependencies": { "inline-style-parser": "0.2.4" @@ -9434,6 +9320,26 @@ "node": ">=14.0.0" } }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9458,19 +9364,16 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" + "tldts": "^6.1.32" }, "engines": { - "node": ">=6" + "node": ">=16" } }, "node_modules/tr46": { @@ -9640,9 +9543,9 @@ } }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", "bin": { @@ -9783,16 +9686,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/update-browserslist-db": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", @@ -9834,17 +9727,6 @@ "punycode": "^2.1.0" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/use-sync-external-store": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", @@ -9883,9 +9765,9 @@ } }, "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -10324,9 +10206,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", - "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "dev": true, "license": "MIT", "engines": { diff --git a/src/frontend/package.json b/src/frontend/package.json index 7c9ac3f70..1aeed1c03 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -2,6 +2,7 @@ "name": "Multi Agent frontend", "version": "0.1.0", "private": true, + "type": "module", "dependencies": { "@fluentui/merge-styles": "^8.6.14", "@fluentui/react-components": "^9.64.0", @@ -14,7 +15,7 @@ "@types/node": "^16.18.126", "@types/react": "^18.3.23", "@types/react-dom": "^18.3.7", - "axios": "^1.9.0", + "axios": "^1.11.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-markdown": "^10.1.0", @@ -62,7 +63,7 @@ "@vitest/ui": "^3.2.4", "eslint": "^8.57.1", "eslint-plugin-react": "^7.37.5", - "jsdom": "^24.1.3", + "jsdom": "^26.1.0", "typescript": "^5.8.3", "vite": "^7.1.2", "vitest": "^3.2.4" diff --git a/src/mcp_server/Dockerfile b/src/mcp_server/Dockerfile index b8e360344..4e98c5bc5 100644 --- a/src/mcp_server/Dockerfile +++ b/src/mcp_server/Dockerfile @@ -42,4 +42,4 @@ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ CMD curl -f http://localhost:9000/health || exit 1 # Run your main script -CMD ["uv", "run", "python", "mcp_server.py", "--transport", "http", "--host", "0.0.0.0", "--port", "9000"] \ No newline at end of file +CMD ["uv", "run", "python", "mcp_server.py", "--transport", "streamable-http", "--host", "0.0.0.0", "--port", "9000"] \ No newline at end of file