diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 86118eb..8270ff5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,15 +1,28 @@ -name: Validate Deployment +name: Deploy-Test-Cleanup Pipeline on: - push: - branches: - - main - schedule: - - cron: '0 5,17 * * *' # Runs at 5:00 AM and 5:00 PM GMT + workflow_run: + workflows: ["Build Docker and Optional Push"] + types: + - completed + branches: + - main + - dev + - demo + schedule: + - cron: '0 5,17 * * *' # Runs at 5:00 AM and 5:00 PM GMT + workflow_dispatch: + +env: + GPT_MIN_CAPACITY: 200 + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} jobs: deploy: runs-on: ubuntu-latest + outputs: + RESOURCE_GROUP_NAME: ${{ steps.check_create_rg.outputs.RESOURCE_GROUP_NAME }} + WEBAPP_URL: ${{ steps.get_output.outputs.WEBAPP_URL }} steps: - name: Checkout Code uses: actions/checkout@v3 @@ -35,7 +48,6 @@ jobs: UNIQUE_RG_NAME="arg-${ACCL_NAME}-${SHORT_UUID}" echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV echo "Generated RESOURCE_GROUP_NAME: ${UNIQUE_RG_NAME}" - - name: Check and Create Resource Group id: check_create_rg @@ -49,8 +61,8 @@ jobs: else echo "Resource group already exists." fi + echo "RESOURCE_GROUP_NAME=${{ env.RESOURCE_GROUP_NAME }}" >> $GITHUB_OUTPUT - - name: Generate Unique Solution Prefix id: generate_solution_prefix run: | @@ -62,16 +74,42 @@ jobs: echo "SOLUTION_PREFIX=${UNIQUE_SOLUTION_PREFIX}" >> $GITHUB_ENV echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}" - - name: Deploy Bicep Template id: deploy run: | set -e + # set image tag based on branch + if [[ "${{ env.BRANCH_NAME }}" == "main" ]]; then + IMAGE_TAG="latest" + elif [[ "${{ env.BRANCH_NAME }}" == "dev" ]]; then + IMAGE_TAG="dev" + elif [[ "${{ env.BRANCH_NAME }}" == "demo" ]]; then + IMAGE_TAG="demo" + else + IMAGE_TAG="latest" + fi + az deployment group create \ + --name ${{ env.SOLUTION_PREFIX }}-deployment \ --resource-group ${{ env.RESOURCE_GROUP_NAME }} \ --template-file infra/main.bicep \ - --parameters AzureAiServiceLocation=northcentralus Prefix=${{ env.SOLUTION_PREFIX }} - + --parameters \ + Prefix="${{ env.SOLUTION_PREFIX }}" \ + AzureAiServiceLocation="eastus" \ + capacity=${{ env.GPT_MIN_CAPACITY }} \ + imageVersion="${IMAGE_TAG}"\ + --debug + + - name: Get Deployment Output and extract Values + id: get_output + run: | + set -e + echo "Fetching deployment output..." + BICEP_OUTPUT=$(az deployment group show --name ${{ env.SOLUTION_PREFIX }}-deployment --resource-group ${{ env.RESOURCE_GROUP_NAME }} --query "properties.outputs" -o json) + echo "Extracting deployment output..." + WEBAPP_URL=$(echo $BICEP_OUTPUT | jq -r '.weB_APP_URL.value') + echo "WEBAPP_URL=$WEBAPP_URL" >> $GITHUB_OUTPUT + echo "Deployment output: $BICEP_OUTPUT" - name: Send Notification on Failure if: failure() @@ -91,8 +129,37 @@ jobs: -H "Content-Type: application/json" \ -d "$EMAIL_BODY" || echo "Failed to send notification" + - name: Logout from Azure + if: always() + run: | + az logout + echo "Logged out from Azure." + + e2e-test: + needs: deploy + uses: ./.github/workflows/test-automation.yml + with: + CODEMOD_WEB_URL: ${{ needs.deploy.outputs.WEBAPP_URL }} + secrets: inherit + + cleanup-deployment: + if: always() && needs.deploy.outputs.RESOURCE_GROUP_NAME != '' + needs: [deploy, e2e-test] + runs-on: ubuntu-latest + env: + RESOURCE_GROUP_NAME: ${{ needs.deploy.outputs.RESOURCE_GROUP_NAME }} + steps: + - name: Setup Azure CLI + run: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + az --version # Verify installation + + - name: Login to Azure + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} - name: Get Log Analytics Workspace and OpenAI from Resource Group + if: always() id: get_azure_resources run: | @@ -123,8 +190,8 @@ jobs: echo "OpenAI resource name: ${openai_resource_name}" fi - - name: List KeyVaults and Store in Array + if: always() id: list_keyvaults run: | @@ -158,6 +225,7 @@ jobs: fi - name: Purge log analytics workspace + if: always() id: log_analytics_workspace run: | @@ -172,9 +240,8 @@ jobs: echo "Log analytics workspace resource purging completed successfully" - - name: Delete Bicep Deployment - if: success() + if: always() run: | set -e echo "Checking if resource group exists..." @@ -190,8 +257,8 @@ jobs: echo "Resource group does not exists." fi - - name: Wait for resource deletion to complete + if: always() run: | # List of keyvaults @@ -249,10 +316,9 @@ jobs: break fi done - - name: Purging the Resources - if: success() + if: always() run: | set -e @@ -296,3 +362,9 @@ jobs: fi done echo "Resource purging completed successfully" + + - name: Logout from Azure + if: always() + run: | + az logout + echo "Logged out from Azure." \ No newline at end of file diff --git a/.github/workflows/test-automation.yml b/.github/workflows/test-automation.yml index 4922318..8539762 100644 --- a/.github/workflows/test-automation.yml +++ b/.github/workflows/test-automation.yml @@ -1,23 +1,23 @@ name: Test Automation Code Modernization on: - push: - branches: - - main - - dev - paths: - - 'tests/e2e-test/**' - schedule: - - cron: '0 13 * * *' # Runs at 1 PM UTC - workflow_dispatch: + workflow_call: + inputs: + CODEMOD_WEB_URL: + required: true + type: string + description: "Web URL for Code Modernization" + secrets: + EMAILNOTIFICATION_LOGICAPP_URL_TA: + required: false + description: "Logic App URL for email notifications" env: - url: ${{ vars.CODEMOD_WEB_URL }} - accelerator_name: "Code Modernization" + url: ${{ inputs.CODEMOD_WEB_URL }} + accelerator_name: "Code Modernization" jobs: test: - runs-on: ubuntu-latest steps: - name: Checkout repository @@ -33,15 +33,6 @@ jobs: with: creds: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}","clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}","subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}","tenantId":"${{ secrets.AZURE_TENANT_ID }}"}' - - name: Start Container App - id: start-container-app - uses: azure/cli@v2 - with: - azcliversion: 'latest' - inlineScript: | - az rest -m post -u "/subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/resourceGroups/${{ vars.CODEMOD_RG }}/providers/Microsoft.App/containerApps/${{ vars.CODEMOD_FRONTEND_CONTAINER_NAME }}/start?api-version=2025-01-01" - az rest -m post -u "/subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/resourceGroups/${{ vars.CODEMOD_RG }}/providers/Microsoft.App/containerApps/${{ vars.CODEMOD_BACKEND_CONTAINER_NAME }}/start?api-version=2025-01-01" - - name: Install dependencies run: | python -m pip install --upgrade pip @@ -50,6 +41,11 @@ jobs: - name: Ensure browsers are installed run: python -m playwright install --with-deps chromium + - name: Open URL + run: | + echo "Opening URL: ${{ env.url }}" + python -m webbrowser "${{ env.url }}" + - name: Run tests(1) id: test1 run: | @@ -118,14 +114,4 @@ jobs: # Send the notification curl -X POST "${{ secrets.EMAILNOTIFICATION_LOGICAPP_URL_TA }}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send notification" - - - name: Stop Container App - if: always() - uses: azure/cli@v2 - with: - azcliversion: 'latest' - inlineScript: | - az rest -m post -u "/subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/resourceGroups/${{ vars.CODEMOD_RG }}/providers/Microsoft.App/containerApps/${{ vars.CODEMOD_FRONTEND_CONTAINER_NAME }}/stop?api-version=2025-01-01" - az rest -m post -u "/subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/resourceGroups/${{ vars.CODEMOD_RG }}/providers/Microsoft.App/containerApps/${{ vars.CODEMOD_BACKEND_CONTAINER_NAME }}/stop?api-version=2025-01-01" - az logout \ No newline at end of file + -d "$EMAIL_BODY" || echo "Failed to send notification" \ No newline at end of file diff --git a/infra/main.bicep b/infra/main.bicep index 79933cb..cfcfa6a 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -560,7 +560,7 @@ module deploymentScriptCLI 'br/public:avm/res/resources/deployment-script:0.5.1' } output AZURE_AIFOUNDRY_NAME string = azureAiServices.name - +output WEB_APP_URL string = 'https://${containerAppFrontend.outputs.fqdn}' output aiFoundryName string = aiFoundryName output aiProjectName string = aiFoundryProject.name output projectEndpointString string = aiFoundryProject.properties.endpoints['AI Foundry API'] diff --git a/infra/main.json b/infra/main.json index ab72560..9f8f21c 100644 --- a/infra/main.json +++ b/infra/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "0.35.1.17967", - "templateHash": "13571363186442322406" + "templateHash": "17669563175804664564" } }, "parameters": { @@ -50,6 +50,10 @@ "description": "Capacity of the GPT deployment:" } }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "" + }, "deploymentType": { "type": "string", "defaultValue": "GlobalStandard", @@ -88,6 +92,8 @@ "ai": { "aiSearch": "srch-", "aiServices": "aisa-", + "aiFoundry": "aif-", + "aiFoundryProject": "aifp-", "aiVideoIndexer": "avi-", "machineLearningWorkspace": "mlw-", "openAIService": "oai-", @@ -323,7 +329,10 @@ "containerName": "appstorage", "storageSkuName": "Standard_LRS", "storageContainerName": "[replace(replace(replace(replace(format('{0}cast', variables('ResourcePrefix')), '-', ''), '_', ''), '.', ''), '/', '')]", - "azureAiServicesName": "[format('{0}{1}', variables('abbrs').ai.aiServices, variables('ResourcePrefix'))]", + "aiFoundryName": "[format('{0}{1}', variables('abbrs').ai.aiFoundry, variables('ResourcePrefix'))]", + "aiProjectDescription": "AI foundary project for CPS template", + "aiProjectName": "[format('{0}{1}', variables('abbrs').ai.aiFoundryProject, variables('ResourcePrefix'))]", + "aiProjectFriendlyName": "[variables('aiProjectName')]", "aiModelDeployments": [ { "name": "[parameters('llmModel')]", @@ -344,17 +353,44 @@ "resources": [ { "type": "Microsoft.CognitiveServices/accounts", - "apiVersion": "2024-04-01-preview", - "name": "[variables('azureAiServicesName')]", + "apiVersion": "2025-04-01-preview", + "name": "[variables('aiFoundryName')]", "location": "[parameters('AzureAiServiceLocation')]", "sku": { "name": "S0" }, "kind": "AIServices", + "identity": { + "type": "SystemAssigned" + }, "properties": { - "customSubDomainName": "[variables('azureAiServicesName')]" + "allowProjectManagement": true, + "customSubDomainName": "[variables('aiFoundryName')]", + "networkAcls": { + "defaultAction": "Allow", + "virtualNetworkRules": [], + "ipRules": [] + }, + "publicNetworkAccess": "Enabled", + "disableLocalAuth": false } }, + { + "type": "Microsoft.CognitiveServices/accounts/projects", + "apiVersion": "2025-04-01-preview", + "name": "[format('{0}/{1}', variables('aiFoundryName'), variables('aiProjectName'))]", + "location": "[parameters('AzureAiServiceLocation')]", + "identity": { + "type": "SystemAssigned" + }, + "properties": { + "description": "[variables('aiProjectDescription')]", + "displayName": "[variables('aiProjectFriendlyName')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiFoundryName'))]" + ] + }, { "copy": { "name": "azureAiServicesDeployments", @@ -364,7 +400,7 @@ }, "type": "Microsoft.CognitiveServices/accounts/deployments", "apiVersion": "2023-05-01", - "name": "[format('{0}/{1}', variables('azureAiServicesName'), variables('aiModelDeployments')[copyIndex()].name)]", + "name": "[format('{0}/{1}', variables('aiFoundryName'), variables('aiModelDeployments')[copyIndex()].name)]", "properties": { "model": { "format": "OpenAI", @@ -378,7 +414,7 @@ "capacity": "[variables('aiModelDeployments')[copyIndex()].sku.capacity]" }, "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', variables('azureAiServicesName'))]" + "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiFoundryName'))]" ] }, { @@ -441,7 +477,7 @@ }, { "name": "AZURE_OPENAI_ENDPOINT", - "value": "[format('https://{0}.openai.azure.com/', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_ai_foundry'), '2022-09-01').outputs.aiServicesName.value)]" + "value": "[format('https://{0}.openai.azure.com/', variables('aiFoundryName'))]" }, { "name": "MIGRATOR_AGENT_MODEL_DEPLOY", @@ -477,7 +513,7 @@ }, { "name": "AZURE_AI_AGENT_PROJECT_NAME", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_ai_foundry'), '2022-09-01').outputs.aiProjectName.value]" + "value": "[variables('aiProjectName')]" }, { "name": "AZURE_AI_AGENT_RESOURCE_GROUP_NAME", @@ -488,8 +524,8 @@ "value": "[subscription().subscriptionId]" }, { - "name": "AZURE_AI_AGENT_PROJECT_CONNECTION_STRING", - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_ai_foundry'), '2022-09-01').outputs.projectConnectionString.value]" + "name": "AI_PROJECT_ENDPOINT", + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiFoundryName'), variables('aiProjectName')), '2025-04-01-preview').endpoints['AI Foundry API']]" } ], "resources": { @@ -501,6 +537,7 @@ } }, "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiFoundryName'), variables('aiProjectName'))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_ai_foundry')]", "[resourceId('Microsoft.Resources/deployments', toLower(format('{0}conAppsEnv', variables('ResourcePrefix'))))]", "[resourceId('Microsoft.Resources/deployments', toLower(format('{0}{1}databaseAccount', variables('abbrs').databases.cosmosDBDatabase, variables('ResourcePrefix'))))]", @@ -567,7 +604,8 @@ "name": "[guid(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), 'Storage Blob Data Contributor')]", "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]" + "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" }, "dependsOn": [ "[resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))))]", @@ -577,14 +615,15 @@ { "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', variables('azureAiServicesName'))]", + "scope": "[format('Microsoft.CognitiveServices/accounts/{0}', variables('aiFoundryName'))]", "name": "[guid(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), variables('openAiContributorRoleId'))]", "properties": { "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('openAiContributorRoleId'))]", - "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]" + "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" }, "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', variables('azureAiServicesName'))]", + "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiFoundryName'))]", "[resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))))]" ] }, @@ -606,13 +645,40 @@ { "type": "Microsoft.Authorization/roleAssignments", "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.MachineLearningServices/workspaces/{0}', format('{0}{1}', variables('abbrs').ai.aiHubProject, variables('ResourcePrefix')))]", - "name": "[guid(toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))), resourceId('Microsoft.MachineLearningServices/workspaces', format('{0}{1}', variables('abbrs').ai.aiHubProject, variables('ResourcePrefix'))), resourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee'))]", + "name": "[guid(toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))), resourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee'))]", "properties": { "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '64702f94-c441-49e6-a78b-ef80e0188fee')]", - "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]" + "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))), resourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d'))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d')]", + "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))), resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiFoundryName'), variables('aiProjectName')))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '53ca6127-db72-4b80-b1b0-d745d6d5456d')]", + "principalId": "[reference(resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2023-05-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" }, "dependsOn": [ + "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiFoundryName'), variables('aiProjectName'))]", "[resourceId('Microsoft.App/containerApps', toLower(format('{0}{1}Backend', variables('abbrs').containers.containerApp, variables('ResourcePrefix'))))]" ] }, @@ -851,6 +917,9 @@ "solutionLocation": { "value": "[parameters('AzureAiServiceLocation')]" }, + "aiFoundryName": { + "value": "[variables('aiFoundryName')]" + }, "keyVaultName": { "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_keyvault'), '2022-09-01').outputs.keyvaultName.value]" }, @@ -864,13 +933,19 @@ "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_managed_identity'), '2022-09-01').outputs.managedIdentityOutput.value.objectId]" }, "aiServicesEndpoint": { - "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', variables('azureAiServicesName')), '2024-04-01-preview').endpoint]" + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts', variables('aiFoundryName')), '2025-04-01-preview').endpoint]" }, "aiServicesKey": { - "value": "[listKeys(resourceId('Microsoft.CognitiveServices/accounts', variables('azureAiServicesName')), '2024-04-01-preview').key1]" + "value": "[listKeys(resourceId('Microsoft.CognitiveServices/accounts', variables('aiFoundryName')), '2025-04-01-preview').key1]" }, "aiServicesId": { - "value": "[resourceId('Microsoft.CognitiveServices/accounts', variables('azureAiServicesName'))]" + "value": "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiFoundryName'))]" + }, + "existingLogAnalyticsWorkspaceId": { + "value": "[parameters('existingLogAnalyticsWorkspaceId')]" + }, + "aureaiFoundryEndpoint": { + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiFoundryName'), variables('aiProjectName')), '2025-04-01-preview').endpoints['AI Foundry API']]" } }, "template": { @@ -880,7 +955,7 @@ "_generator": { "name": "bicep", "version": "0.35.1.17967", - "templateHash": "6185941478702970428" + "templateHash": "12967265180986066679" } }, "parameters": { @@ -915,6 +990,16 @@ }, "aiServicesId": { "type": "string" + }, + "aureaiFoundryEndpoint": { + "type": "string" + }, + "aiFoundryName": { + "type": "string" + }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "" } }, "variables": { @@ -922,6 +1007,8 @@ "ai": { "aiSearch": "srch-", "aiServices": "aisa-", + "aiFoundry": "aif-", + "aiFoundryProject": "aifp-", "aiVideoIndexer": "avi-", "machineLearningWorkspace": "mlw-", "openAIService": "oai-", @@ -1145,45 +1232,23 @@ "virtualDesktopScalingPlan": "vdscaling-" } }, + "useExisting": "[not(empty(parameters('existingLogAnalyticsWorkspaceId')))]", + "existingLawSubscription": "[if(variables('useExisting'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[2], '')]", + "existingLawResourceGroup": "[if(variables('useExisting'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[4], '')]", + "existingLawName": "[if(variables('useExisting'), split(parameters('existingLogAnalyticsWorkspaceId'), '/')[8], '')]", "abbrs": "[variables('$fxv#0')]", "storageName": "[format('{0}{1}', variables('abbrs').storage.storageAccount, parameters('solutionName'))]", "storageSkuName": "Standard_LRS", - "aiServicesName": "[format('{0}{1}', variables('abbrs').ai.aiServices, parameters('solutionName'))]", "workspaceName": "[format('{0}{1}', variables('abbrs').managementGovernance.logAnalyticsWorkspace, parameters('solutionName'))]", "keyvaultName": "[format('{0}{1}', variables('abbrs').security.keyVault, parameters('solutionName'))]", "location": "[parameters('solutionLocation')]", - "azureAiHubName": "[format('{0}{1}', variables('abbrs').ai.aiHub, parameters('solutionName'))]", - "aiHubFriendlyName": "[variables('azureAiHubName')]", - "aiHubDescription": "AI Hub for KM template", - "aiProjectName": "[format('{0}{1}', variables('abbrs').ai.aiHubProject, parameters('solutionName'))]", - "aiProjectFriendlyName": "[variables('aiProjectName')]", "aiSearchName": "[format('{0}-search', parameters('solutionName'))]", "applicationInsightsName": "[format('{0}-appi', parameters('solutionName'))]", "storageNameCleaned": "[replace(replace(replace(replace(format('{0}cast', variables('storageName')), '-', ''), '_', ''), '.', ''), '/', '')]" }, "resources": [ { - "type": "Microsoft.MachineLearningServices/workspaces/connections", - "apiVersion": "2024-07-01-preview", - "name": "[format('{0}/{1}', variables('azureAiHubName'), format('{0}-connection-AzureOpenAI', variables('azureAiHubName')))]", - "properties": { - "category": "AIServices", - "target": "[parameters('aiServicesEndpoint')]", - "authType": "ApiKey", - "isSharedToAll": true, - "credentials": { - "key": "[parameters('aiServicesKey')]" - }, - "metadata": { - "ApiType": "Azure", - "ResourceId": "[parameters('aiServicesId')]" - } - }, - "dependsOn": [ - "[resourceId('Microsoft.MachineLearningServices/workspaces', variables('azureAiHubName'))]" - ] - }, - { + "condition": "[not(variables('useExisting'))]", "type": "Microsoft.OperationalInsights/workspaces", "apiVersion": "2023-09-01", "name": "[variables('workspaceName')]", @@ -1212,109 +1277,6 @@ "[resourceId('Microsoft.OperationalInsights/workspaces', variables('workspaceName'))]" ] }, - { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2022-09-01", - "name": "[variables('storageNameCleaned')]", - "location": "[variables('location')]", - "sku": { - "name": "[variables('storageSkuName')]" - }, - "kind": "StorageV2", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "accessTier": "Hot", - "allowBlobPublicAccess": false, - "allowCrossTenantReplication": false, - "allowSharedKeyAccess": false, - "encryption": { - "keySource": "Microsoft.Storage", - "requireInfrastructureEncryption": false, - "services": { - "blob": { - "enabled": true, - "keyType": "Account" - }, - "file": { - "enabled": true, - "keyType": "Account" - }, - "queue": { - "enabled": true, - "keyType": "Service" - }, - "table": { - "enabled": true, - "keyType": "Service" - } - } - }, - "isHnsEnabled": false, - "isNfsV3Enabled": false, - "keyPolicy": { - "keyExpirationPeriodInDays": 7 - }, - "largeFileSharesState": "Disabled", - "minimumTlsVersion": "TLS1_2", - "networkAcls": { - "bypass": "AzureServices", - "defaultAction": "Allow" - }, - "supportsHttpsTrafficOnly": true - } - }, - { - "type": "Microsoft.Authorization/roleAssignments", - "apiVersion": "2022-04-01", - "scope": "[format('Microsoft.Storage/storageAccounts/{0}', variables('storageNameCleaned'))]", - "name": "[guid(resourceGroup().id, parameters('managedIdentityObjectId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'))]", - "properties": { - "principalId": "[parameters('managedIdentityObjectId')]", - "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe')]", - "principalType": "ServicePrincipal" - }, - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', variables('storageNameCleaned'))]" - ] - }, - { - "type": "Microsoft.MachineLearningServices/workspaces", - "apiVersion": "2023-08-01-preview", - "name": "[variables('azureAiHubName')]", - "location": "[variables('location')]", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "friendlyName": "[variables('aiHubFriendlyName')]", - "description": "[variables('aiHubDescription')]", - "keyVault": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", - "storageAccount": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageNameCleaned'))]" - }, - "kind": "hub", - "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', variables('storageNameCleaned'))]" - ] - }, - { - "type": "Microsoft.MachineLearningServices/workspaces", - "apiVersion": "2024-01-01-preview", - "name": "[variables('aiProjectName')]", - "location": "[variables('location')]", - "kind": "Project", - "identity": { - "type": "SystemAssigned" - }, - "properties": { - "friendlyName": "[variables('aiProjectFriendlyName')]", - "hubResourceId": "[resourceId('Microsoft.MachineLearningServices/workspaces', variables('azureAiHubName'))]" - }, - "dependsOn": [ - "[resourceId('Microsoft.MachineLearningServices/workspaces', variables('azureAiHubName'))]" - ] - }, { "type": "Microsoft.KeyVault/vaults/secrets", "apiVersion": "2021-11-01-preview", @@ -1374,13 +1336,10 @@ { "type": "Microsoft.KeyVault/vaults/secrets", "apiVersion": "2021-11-01-preview", - "name": "[format('{0}/{1}', parameters('keyVaultName'), 'AZURE-AI-PROJECT-CONN-STRING')]", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'AI-PROJECT-ENDPOINT')]", "properties": { - "value": "[format('{0};{1};{2};{3}', split(reference(resourceId('Microsoft.MachineLearningServices/workspaces', variables('aiProjectName')), '2024-01-01-preview').discoveryUrl, '/')[2], subscription().subscriptionId, resourceGroup().name, variables('aiProjectName'))]" - }, - "dependsOn": [ - "[resourceId('Microsoft.MachineLearningServices/workspaces', variables('aiProjectName'))]" - ] + "value": "[parameters('aureaiFoundryEndpoint')]" + } }, { "type": "Microsoft.KeyVault/vaults/secrets", @@ -1419,7 +1378,7 @@ "apiVersion": "2021-11-01-preview", "name": "[format('{0}/{1}', parameters('keyVaultName'), 'COG-SERVICES-NAME')]", "properties": { - "value": "[variables('aiServicesName')]" + "value": "[parameters('aiFoundryName')]" } }, { @@ -1456,43 +1415,28 @@ "type": "string", "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" }, - "aiServicesName": { - "type": "string", - "value": "[variables('aiServicesName')]" - }, "aiSearchName": { "type": "string", "value": "[variables('aiSearchName')]" }, - "aiProjectName": { - "type": "string", - "value": "[variables('aiProjectName')]" - }, "storageAccountName": { "type": "string", "value": "[variables('storageNameCleaned')]" }, "logAnalyticsId": { "type": "string", - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', variables('workspaceName'))]" - }, - "storageAccountId": { - "type": "string", - "value": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageNameCleaned'))]" + "value": "[if(variables('useExisting'), extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('existingLawSubscription'), variables('existingLawResourceGroup')), 'Microsoft.OperationalInsights/workspaces', variables('existingLawName')), resourceId('Microsoft.OperationalInsights/workspaces', variables('workspaceName')))]" }, "applicationInsightsConnectionString": { "type": "string", "value": "[reference(resourceId('Microsoft.Insights/components', variables('applicationInsightsName')), '2020-02-02').ConnectionString]" - }, - "projectConnectionString": { - "type": "string", - "value": "[format('{0};{1};{2};{3}', split(reference(resourceId('Microsoft.MachineLearningServices/workspaces', variables('aiProjectName')), '2024-01-01-preview').discoveryUrl, '/')[2], subscription().subscriptionId, resourceGroup().name, variables('aiProjectName'))]" } } } }, "dependsOn": [ - "[resourceId('Microsoft.CognitiveServices/accounts', variables('azureAiServicesName'))]", + "[resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiFoundryName'), variables('aiProjectName'))]", + "[resourceId('Microsoft.CognitiveServices/accounts', variables('aiFoundryName'))]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_keyvault')]", "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_managed_identity')]" ] @@ -7725,5 +7669,27 @@ "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', 'deploy_managed_identity')]" ] } - ] + ], + "outputs": { + "AZURE_AIFOUNDRY_NAME": { + "type": "string", + "value": "[variables('aiFoundryName')]" + }, + "WEB_APP_URL": { + "type": "string", + "value": "[format('https://{0}', reference(resourceId('Microsoft.Resources/deployments', toLower(format('{0}{1}containerAppFrontend', variables('abbrs').containers.containerApp, variables('ResourcePrefix')))), '2022-09-01').outputs.fqdn.value)]" + }, + "aiFoundryName": { + "type": "string", + "value": "[variables('aiFoundryName')]" + }, + "aiProjectName": { + "type": "string", + "value": "[variables('aiProjectName')]" + }, + "projectEndpointString": { + "type": "string", + "value": "[reference(resourceId('Microsoft.CognitiveServices/accounts/projects', variables('aiFoundryName'), variables('aiProjectName')), '2025-04-01-preview').endpoints['AI Foundry API']]" + } + } } \ No newline at end of file