Skip to content

Commit 3d57436

Browse files
Merge pull request #49 from microsoft/dev
fix: merging dev to main
2 parents 5dbd9b2 + 9fc4caa commit 3d57436

8 files changed

Lines changed: 1909 additions & 16 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ on:
55
- main
66
- dev
77
- demo
8+
pull_request:
9+
branches:
10+
- dev
811
schedule:
912
- cron: '0 9,21 * * *' # Runs at 9:00 AM and 9:00 PM GMT
1013
workflow_dispatch: # Allow manual triggering
@@ -113,7 +116,8 @@ jobs:
113116
--parameters solutionName=${{env.SOLUTION_PREFIX}} \
114117
--parameters location=${{ env.AZURE_LOCATION }} \
115118
--parameters aiDeploymentLocation=${{ env.AZURE_LOCATION }} \
116-
--parameters azureAiServiceLocation=${{ env.AZURE_LOCATION }}
119+
--parameters azureAiServiceLocation=${{ env.AZURE_LOCATION }} \
120+
--parameters createdBy="pipeline" \
117121
118122
119123
- name: Extract AI Services and Key Vault Names

azure_custom.yaml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
2+
3+
# This file contains a developer‑focused Azure Developer CLI configuration. It
4+
# extends the default template by defining three services (backend API,
5+
# processor and frontend) and instructs azd to build container images from
6+
# your local source code. All three services are packaged as container apps
7+
# using the Dockerfiles located in their respective project directories.
8+
# After deployment a post‑deploy hook prints the endpoints of the deployed
9+
# container apps.
10+
11+
name: container-migration-solution-accelerator
12+
metadata:
13+
template: container-migration-solution-accelerator@1.0
14+
15+
requiredVersions:
16+
# Require a recent version of azd that supports the packaging
17+
# functionality used here. Versions less than 1.17.1 had a bug in
18+
# remoteBuild.
19+
azd: ">=1.18.2"
20+
21+
infra:
22+
parameters:
23+
backendImageName: ${SERVICE_BACKEND_IMAGE_NAME}
24+
processorImageName: ${SERVICE_PROCESSOR_IMAGE_NAME}
25+
frontendImageName: ${SERVICE_FRONTEND_IMAGE_NAME}
26+
27+
services:
28+
# Backend API service. This is a Python FastAPI application defined in
29+
# src/backend-api. The azd packaging stage builds a Docker image using
30+
# the Dockerfile in that directory. The image name 'backend-api' is
31+
# combined with the automatically created Azure Container Registry login
32+
# server to form the final image reference.
33+
backend:
34+
project: ./src/backend-api
35+
language: py
36+
host: containerapp
37+
docker:
38+
image: backend-api
39+
remoteBuild: true
40+
41+
# Processor service. This service reads messages from storage queues and
42+
# orchestrates long‑running migrations. It is also packaged as a
43+
# container and deployed to a container app environment. The Dockerfile
44+
# in the src/processor directory defines how the image is built.
45+
processor:
46+
project: ./src/processor
47+
language: py
48+
host: containerapp
49+
docker:
50+
image: processor
51+
remoteBuild: true
52+
53+
# Frontend service. The frontend consists of a React single‑page
54+
# application and a lightweight Python server that serves the compiled
55+
# assets. azd packages the frontend by building a Docker image using
56+
# the Dockerfile in the src/frontend directory and deploys it to a
57+
# container app.
58+
frontend:
59+
project: ./src/frontend
60+
language: py
61+
host: containerapp
62+
docker:
63+
image: frontend
64+
remoteBuild: true
65+
66+
hooks:
67+
# After deployment prints the names and endpoints of the deployed
68+
# container apps. This reproduces the behaviour of the default
69+
# configuration so that developers can easily discover their services.
70+
postdeploy:
71+
posix:
72+
shell: sh
73+
run: |
74+
echo "-----"
75+
echo "🧭 Frontend Container App Details:"
76+
echo "✅ Name: $CONTAINER_FRONTEND_APP_NAME"
77+
echo "🌐 Endpoint: https://$CONTAINER_FRONTEND_APP_FQDN"
78+
echo "🔗 Portal URL: https://portal.azure.com/#resource/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$AZURE_RESOURCE_GROUP/providers/Microsoft.App/containerApps/$CONTAINER_FRONTEND_APP_NAME"
79+
echo "-----"
80+
echo "🧭 Backend API Container App Details:"
81+
echo "✅ Name: $CONTAINER_API_APP_NAME"
82+
echo "🌐 Endpoint: https://$CONTAINER_API_APP_FQDN"
83+
echo "🔗 Portal URL: https://portal.azure.com/#resource/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$AZURE_RESOURCE_GROUP/providers/Microsoft.App/containerApps/$CONTAINER_API_APP_NAME"
84+
echo "-----"
85+
echo "🧭 Processor Container App Details:"
86+
echo "✅ Name: $SERVICE_PROCESSOR_NAME"
87+
echo "🔗 Portal URL: https://portal.azure.com/#resource/subscriptions/$AZURE_SUBSCRIPTION_ID/resourceGroups/$AZURE_RESOURCE_GROUP/providers/Microsoft.App/containerApps/$SERVICE_PROCESSOR_NAME"
88+
echo "-----"
89+
interactive: true
90+
windows:
91+
shell: pwsh
92+
run: |
93+
Write-Host "-----"
94+
Write-Host "🧭 Frontend Container App Details:"
95+
Write-Host "✅ Name: $env:CONTAINER_FRONTEND_APP_NAME"
96+
Write-Host "🌐 Endpoint: https://$env:CONTAINER_FRONTEND_APP_FQDN"
97+
Write-Host "🔗 Portal URL: https://portal.azure.com/#resource/subscriptions/$env:AZURE_SUBSCRIPTION_ID/resourceGroups/$env:AZURE_RESOURCE_GROUP/providers/Microsoft.App/containerApps/$env:CONTAINER_FRONTEND_APP_NAME" -ForegroundColor Cyan
98+
Write-Host "-----"
99+
Write-Host "🧭 Backend API Container App Details:"
100+
Write-Host "✅ Name: $env:CONTAINER_API_APP_NAME"
101+
Write-Host "🌐 Endpoint: https://$env:CONTAINER_API_APP_FQDN"
102+
Write-Host "🔗 Portal URL: https://portal.azure.com/#resource/subscriptions/$env:AZURE_SUBSCRIPTION_ID/resourceGroups/$env:AZURE_RESOURCE_GROUP/providers/Microsoft.App/containerApps/$env:CONTAINER_API_APP_NAME" -ForegroundColor Cyan
103+
Write-Host "-----"
104+
Write-Host "🧭 Processor Container App Details:"
105+
Write-Host "✅ Name: $env:SERVICE_PROCESSOR_NAME"
106+
Write-Host "🔗 Portal URL: https://portal.azure.com/#resource/subscriptions/$env:AZURE_SUBSCRIPTION_ID/resourceGroups/$env:AZURE_RESOURCE_GROUP/providers/Microsoft.App/containerApps/$env:SERVICE_PROCESSOR_NAME" -ForegroundColor Cyan
107+
Write-Host "-----"
108+
interactive: true

docs/DeploymentGuide.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ After successful deployment:
315315
```shell
316316
azd down
317317
```
318+
> **Note:** If you deployed with `enableRedundancy=true` and Log Analytics workspace replication is enabled, you must first disable replication before running `azd down` else resource group delete will fail. Follow the steps in [Handling Log Analytics Workspace Deletion with Replication Enabled](./LogAnalyticsReplicationDisable.md), wait until replication returns `false`, then run `azd down`.
318319
319320
### Manual Cleanup (if needed)
320321
If deployment fails or you need to clean up manually:
@@ -430,3 +431,10 @@ azd env get-values
430431
- 🐛 **Issues:** Check [Troubleshooting Guide](./TroubleShootingSteps.md)
431432
- 💬 **Support:** Review [Support Guidelines](../SUPPORT.md)
432433
- 🔧 **Development:** See [Contributing Guide](../CONTRIBUTING.md)
434+
435+
### Deploy Your local changes
436+
To Deploy your local changes rename the below files.
437+
438+
Rename `azure.yaml` to `azure_custom2.yaml` and `azure_custom.yaml` to `azure.yaml`.
439+
Go to `infra` directory
440+
Rename `main.bicep` to `main_custom2.bicep` and `main_custom.bicep` to `main.bicep`. Continue with the [deploying steps](#deploying-with-azd).
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# 🛠 Handling Log Analytics Workspace Deletion with Replication Enabled
2+
3+
If redundancy (replication) is enabled for your Log Analytics workspace, you must disable it before deleting the workspace or resource group. Otherwise, deletion will fail.
4+
5+
## ✅ Steps to Disable Replication Before Deletion
6+
Run the following Azure CLI command. Note: This operation may take about 5 minutes to complete.
7+
8+
```bash
9+
az resource update --ids "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{logAnalyticsName}" --set properties.replication.enabled=false
10+
```
11+
12+
Replace:
13+
- `{subscriptionId}` → Your Azure subscription ID
14+
- `{resourceGroupName}` → The name of your resource group
15+
- `{logAnalyticsName}` → The name of your Log Analytics workspace
16+
17+
Optional: Verify replication disabled (should output `false`):
18+
```bash
19+
az resource show --ids "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.OperationalInsights/workspaces/{logAnalyticsName}" --query properties.replication.enabled -o tsv
20+
```
21+
22+
## ✅ After Disabling Replication
23+
You can safely delete:
24+
- The Log Analytics workspace (manual)
25+
- The resource group (manual), or
26+
- All provisioned resources via `azd down`
27+
28+
Return to: [Deployment Guide](./DeploymentGuide.md)

infra/main.bicep

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ param azureAiServiceLocation string
5353
'westus3'
5454
])
5555
@description('Required. Azure region for AI model deployment. Should match azureAiServiceLocation for optimal performance.')
56+
#disable-next-line no-unused-params
5657
param aiDeploymentLocation string = azureAiServiceLocation
5758

5859
@description('Optional. The host (excluding https://) of an existing container registry. This is the `loginServer` when using Azure Container Registry.')
@@ -99,9 +100,12 @@ param cosmosLocation string = 'eastus2'
99100
param existingLogAnalyticsWorkspaceId string = ''
100101

101102
@description('Tag, Created by user name')
102-
param createdBy string = contains(deployer(), 'userPrincipalName')
103-
? split(deployer().userPrincipalName, '@')[0]
104-
: deployer().objectId
103+
param createdBy string = deployer().objectId
104+
105+
// Get the current deployer's information for local debugging permissions
106+
var deployerInfo = deployer()
107+
var deployingUserPrincipalId = deployerInfo.objectId
108+
var deployingUserType = contains(deployerInfo, 'userPrincipalName') ? 'User' : 'ServicePrincipal'
105109

106110
@description('Optional. Resource ID of an existing Foundry project')
107111
param existingFoundryProjectResourceId string = ''
@@ -469,6 +473,17 @@ module storageAccount 'br/public:avm/res/storage/storage-account:0.20.0' = {
469473
principalId: appIdentity.outputs.principalId
470474
principalType: 'ServicePrincipal'
471475
}
476+
// Add deployer permissions
477+
{
478+
roleDefinitionIdOrName: 'Storage Blob Data Contributor'
479+
principalId: deployingUserPrincipalId
480+
principalType: deployingUserType
481+
}
482+
{
483+
roleDefinitionIdOrName: 'Storage Queue Data Contributor'
484+
principalId: deployingUserPrincipalId
485+
principalType: deployingUserType
486+
}
472487
]
473488
// WAF aligned networking
474489
networkAcls: {
@@ -655,6 +670,12 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.15.0' = {
655670
principalType: 'ServicePrincipal'
656671
roleDefinitionIdOrName: 'DocumentDB Account Contributor'
657672
}
673+
// Add deployer for local debugging
674+
{
675+
principalId: deployingUserPrincipalId
676+
principalType: deployingUserType
677+
roleDefinitionIdOrName: 'DocumentDB Account Contributor'
678+
}
658679
]
659680
// Create custom data plane role definition and assignment
660681
dataPlaneRoleDefinitions: [
@@ -669,6 +690,8 @@ module cosmosDb 'br/public:avm/res/document-db/database-account:0.15.0' = {
669690
]
670691
assignments: [
671692
{ principalId: appIdentity.outputs.principalId }
693+
// ADD THIS for local debugging support:
694+
{ principalId: deployingUserPrincipalId }
672695
]
673696
}
674697
]
@@ -699,7 +722,7 @@ module existingAiFoundryAiServicesDeployments 'modules/ai-services-deployments.b
699722
name: take('module.ai-services-model-deployments.${existingAiFoundryAiServices.name}', 64)
700723
scope: resourceGroup(aiFoundryAiServicesSubscriptionId, aiFoundryAiServicesResourceGroupName)
701724
params: {
702-
name: existingAiFoundryAiServices.name
725+
name: aiFoundryAiServicesResourceName // Fix: use variable instead of resource reference
703726
deployments: [
704727
{
705728
name: aiModelDeploymentName
@@ -715,6 +738,7 @@ module existingAiFoundryAiServicesDeployments 'modules/ai-services-deployments.b
715738
}
716739
]
717740
roleAssignments: [
741+
// Service Principal permissions
718742
{
719743
principalId: appIdentity.outputs.principalId
720744
principalType: 'ServicePrincipal'
@@ -723,12 +747,23 @@ module existingAiFoundryAiServicesDeployments 'modules/ai-services-deployments.b
723747
{
724748
principalId: appIdentity.outputs.principalId
725749
principalType: 'ServicePrincipal'
726-
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee' // Azure AI Developer
750+
roleDefinitionIdOrName: '64702f94-c441-49e6-a78b-ef80e0188fee'
727751
}
728752
{
729753
principalId: appIdentity.outputs.principalId
730754
principalType: 'ServicePrincipal'
731-
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User
755+
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d'
756+
}
757+
// Deployer permissions
758+
{
759+
principalId: deployingUserPrincipalId
760+
principalType: deployingUserType
761+
roleDefinitionIdOrName: 'Cognitive Services OpenAI Contributor'
762+
}
763+
{
764+
principalId: deployingUserPrincipalId
765+
principalType: deployingUserType
766+
roleDefinitionIdOrName: 'Cognitive Services User'
732767
}
733768
]
734769
}
@@ -746,6 +781,7 @@ module aiFoundry 'br/public:avm/ptn/ai-ml/ai-foundry:0.4.0' = if(!useExistingAiF
746781
accountName:aiFoundryAiServicesResourceName
747782
allowProjectManagement: true
748783
roleAssignments: [
784+
// Service Principal permissions
749785
{
750786
principalId: appIdentity.outputs.principalId
751787
principalType: 'ServicePrincipal'
@@ -761,6 +797,17 @@ module aiFoundry 'br/public:avm/ptn/ai-ml/ai-foundry:0.4.0' = if(!useExistingAiF
761797
principalType: 'ServicePrincipal'
762798
roleDefinitionIdOrName: '53ca6127-db72-4b80-b1b0-d745d6d5456d' // Azure AI User
763799
}
800+
// Deployer permissions for local debugging
801+
{
802+
principalId: deployingUserPrincipalId
803+
principalType: deployingUserType
804+
roleDefinitionIdOrName: 'Cognitive Services OpenAI Contributor'
805+
}
806+
{
807+
principalId: deployingUserPrincipalId
808+
principalType: deployingUserType
809+
roleDefinitionIdOrName: 'Cognitive Services User'
810+
}
764811
]
765812
// Remove networking configuration to avoid AML workspace creation issues
766813
networking: enablePrivateNetworking? {
@@ -791,7 +838,7 @@ module aiFoundry 'br/public:avm/ptn/ai-ml/ai-foundry:0.4.0' = if(!useExistingAiF
791838
}
792839
}
793840

794-
var aiServicesName = useExistingAiFoundryAiProject ? existingAiFoundryAiServices.name : aiFoundry.outputs.aiServicesName
841+
var aiServicesName = useExistingAiFoundryAiProject ? existingAiFoundryAiServices.name : aiFoundryAiServicesResourceName
795842
module appConfiguration 'br/public:avm/res/app-configuration/configuration-store:0.9.1' = {
796843
name: take('avm.res.app-config.store.${solutionSuffix}', 64)
797844
params: {
@@ -898,6 +945,8 @@ module appConfiguration 'br/public:avm/res/app-configuration/configuration-store
898945
sku: 'Standard'
899946
publicNetworkAccess: 'Enabled'
900947
}
948+
// Add explicit dependency
949+
dependsOn: useExistingAiFoundryAiProject ? [] : [aiFoundry]
901950
}
902951

903952
module avmAppConfigUpdated 'br/public:avm/res/app-configuration/configuration-store:0.6.3' = if (enablePrivateNetworking) {
@@ -971,7 +1020,7 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.11.
9711020
platformReservedDnsIP: '172.17.17.17'
9721021
zoneRedundant: (enablePrivateNetworking) ? true : false // Enable zone redundancy if private networking is enabled
9731022
infrastructureSubnetResourceId: (enablePrivateNetworking)
974-
? virtualNetwork.outputs.containersSubnetResourceId // Use the container app subnet
1023+
? virtualNetwork!.outputs.containersSubnetResourceId // Use the container app subnet
9751024
: null // Use the container app subnet
9761025
}
9771026
}
@@ -1210,3 +1259,7 @@ output AZURE_SUBSCRIPTION_ID string = subscription().subscriptionId
12101259

12111260
@description('The Azure resource group name.')
12121261
output AZURE_RESOURCE_GROUP string = resourceGroup().name
1262+
1263+
// Log deployer information for debugging
1264+
output deployerObjectId string = deployingUserPrincipalId
1265+
output deployerType string = deployingUserType

0 commit comments

Comments
 (0)