Skip to content

Commit de2e1e3

Browse files
authored
Support reprovisioning (#220)
* Support reprovisioning * Fix reprovisioning logic for existing AI project resources in Bicep module * Refactor storage account name resolution to use a stable token and update related references
1 parent 219d3c4 commit de2e1e3

File tree

3 files changed

+41
-18
lines changed

3 files changed

+41
-18
lines changed

azure.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
name: azd-get-started-with-ai-agents
66
metadata:
7-
template: azd-get-started-with-ai-agents@2.1.1
7+
template: azd-get-started-with-ai-agents@2.2.0
88
requiredVersions:
99
azd: ">=1.14.0"
1010

infra/core/host/ai-environment.bicep

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ param searchServiceName string = ''
2020
param appInsightConnectionName string
2121
param tags object = {}
2222
param aoaiConnectionName string
23+
@description('Name of the parent deployment (passed from the top-level deployment) used to generate unique nested deployment names.')
24+
param parentDeploymentName string
25+
26+
@description('A per-deployment seed value (passed from the top-level deployment) used to avoid collisions on nested deployment names across retries.')
27+
param deploymentSeed string
28+
29+
var deploymentSuffix = substring(uniqueString(parentDeploymentName, deploymentSeed), 0, 8)
30+
2331
module storageAccount '../storage/storage-account.bicep' = {
2432
name: 'storageAccount'
2533
params: {
@@ -59,7 +67,7 @@ module storageAccount '../storage/storage-account.bicep' = {
5967

6068
module logAnalytics '../monitor/loganalytics.bicep' =
6169
if (!empty(logAnalyticsName)) {
62-
name: 'logAnalytics'
70+
name: 'logAnalytics-${deploymentSuffix}'
6371
params: {
6472
location: location
6573
tags: tags
@@ -69,7 +77,7 @@ module logAnalytics '../monitor/loganalytics.bicep' =
6977

7078
module applicationInsights '../monitor/applicationinsights.bicep' =
7179
if (!empty(applicationInsightsName) && !empty(logAnalyticsName)) {
72-
name: 'applicationInsights'
80+
name: 'applicationInsights-${deploymentSuffix}'
7381
params: {
7482
location: location
7583
tags: tags

infra/main.bicep

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,15 @@ param searchConnectionId string = ''
128128

129129
@description('The name of the blob container for document storage')
130130
param blobContainerName string = 'documents'
131+
param alwaysReprovision bool = false
131132

132133
var abbrs = loadJsonContent('./abbreviations.json')
133134

134135
var resourceToken = templateValidationMode? toLower(uniqueString(subscription().id, environmentName, location, seed)) : toLower(uniqueString(subscription().id, environmentName, location))
135136

137+
// Stable token that never depends on `seed` (and therefore never on `newGuid()`).
138+
var resourceTokenStable = toLower(uniqueString(subscription().id, environmentName, location))
139+
136140
var tags = { 'azd-env-name': environmentName }
137141

138142
var tempAgentID = !empty(aiAgentID) ? aiAgentID : ''
@@ -188,17 +192,21 @@ var logAnalyticsWorkspaceResolvedName = !useApplicationInsights
188192
var resolvedSearchServiceName = !useSearchService
189193
? ''
190194
: !empty(searchServiceName) ? searchServiceName : '${abbrs.searchSearchServices}${resourceToken}'
191-
195+
// Storage account name used when we need to reference an existing storage account (must be deterministic for Bicep diagnostics).
196+
// Note: for normal deployments (templateValidationMode == false), resourceTokenStable == resourceToken.
197+
var resolvedStorageAccountName = !empty(storageAccountName)
198+
? storageAccountName
199+
: '${abbrs.storageStorageAccounts}${resourceTokenStable}'
192200

193-
module ai 'core/host/ai-environment.bicep' = if (empty(azureExistingAIProjectResourceId)) {
201+
module ai 'core/host/ai-environment.bicep' = if (empty(azureExistingAIProjectResourceId) || alwaysReprovision) {
194202
name: 'ai'
195203
scope: rg
196204
params: {
197205
location: location
198206
tags: tags
199-
storageAccountName: !empty(storageAccountName)
200-
? storageAccountName
201-
: '${abbrs.storageStorageAccounts}${resourceToken}'
207+
parentDeploymentName: deployment().name
208+
deploymentSeed: seed
209+
storageAccountName: resolvedStorageAccountName
202210
aiServicesName: !empty(aiServicesName) ? aiServicesName : 'aoai-${resourceToken}'
203211
aiProjectName: !empty(aiProjectName) ? aiProjectName : 'proj-${resourceToken}'
204212
aiServiceModelDeployments: aiDeployments
@@ -224,23 +232,30 @@ var searchServiceEndpoint_final = empty(searchServiceEndpoint) ? searchServiceEn
224232

225233
var searchConnectionId_final = empty(searchConnectionId) ? searchConnectionIdFromAIOutput : searchConnectionId
226234

235+
resource resolvedStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
236+
name: resolvedStorageAccountName
237+
scope: rg
238+
}
239+
240+
var storageAccountResourceId_final = resolvedStorageAccount.id
241+
227242
// If bringing an existing AI project, set up the log analytics workspace here
228-
module logAnalytics 'core/monitor/loganalytics.bicep' = if (!empty(azureExistingAIProjectResourceId)) {
229-
name: 'logAnalytics'
243+
module logAnalytics 'core/monitor/loganalytics.bicep' = if (!empty(azureExistingAIProjectResourceId) && !alwaysReprovision) {
244+
name: 'logAnalytics-${substring(uniqueString(deployment().name, seed), 0, 8)}'
230245
scope: rg
231246
params: {
232247
location: location
233248
tags: tags
234249
name: logAnalyticsWorkspaceResolvedName
235250
}
236251
}
237-
var existingProjEndpoint = !empty(azureExistingAIProjectResourceId) ? format('https://{0}.services.ai.azure.com/api/projects/{1}',split(azureExistingAIProjectResourceId, '/')[8], split(azureExistingAIProjectResourceId, '/')[10]) : ''
252+
var existingProjEndpoint = (!empty(azureExistingAIProjectResourceId) && !alwaysReprovision) ? format('https://{0}.services.ai.azure.com/api/projects/{1}',split(azureExistingAIProjectResourceId, '/')[8], split(azureExistingAIProjectResourceId, '/')[10]) : ''
238253

239-
var projectResourceId = !empty(azureExistingAIProjectResourceId)
254+
var projectResourceId = (!empty(azureExistingAIProjectResourceId) && !alwaysReprovision)
240255
? azureExistingAIProjectResourceId
241256
: ai!.outputs.projectResourceId
242257

243-
var projectEndpoint = !empty(azureExistingAIProjectResourceId)
258+
var projectEndpoint = (!empty(azureExistingAIProjectResourceId) && !alwaysReprovision)
244259
? existingProjEndpoint
245260
: ai!.outputs.aiProjectEndpoint
246261

@@ -258,11 +273,11 @@ module monitoringMetricsContribuitorRoleAzureAIDeveloperRG 'core/security/appins
258273
}
259274
}
260275

261-
resource existingProjectRG 'Microsoft.Resources/resourceGroups@2021-04-01' existing = if (!empty(azureExistingAIProjectResourceId) && contains(azureExistingAIProjectResourceId, '/')) {
276+
resource existingProjectRG 'Microsoft.Resources/resourceGroups@2021-04-01' existing = if (!empty(azureExistingAIProjectResourceId) && !alwaysReprovision && contains(azureExistingAIProjectResourceId, '/')) {
262277
name: split(azureExistingAIProjectResourceId, '/')[4]
263278
}
264279

265-
module userRoleAzureAIDeveloperBackendExistingProjectRG 'core/security/role.bicep' = if (!empty(azureExistingAIProjectResourceId)) {
280+
module userRoleAzureAIDeveloperBackendExistingProjectRG 'core/security/role.bicep' = if (!empty(azureExistingAIProjectResourceId) && !alwaysReprovision) {
266281
name: 'backend-role-azureai-developer-existing-project-rg'
267282
scope: existingProjectRG
268283
params: {
@@ -283,7 +298,7 @@ module containerApps 'core/host/container-apps.bicep' = {
283298
containerRegistryName: '${abbrs.containerRegistryRegistries}${resourceToken}'
284299
tags: tags
285300
containerAppsEnvironmentName: 'containerapps-env-${resourceToken}'
286-
logAnalyticsWorkspaceName: empty(azureExistingAIProjectResourceId)
301+
logAnalyticsWorkspaceName: empty(azureExistingAIProjectResourceId) || alwaysReprovision
287302
? ai!.outputs.logAnalyticsWorkspaceName
288303
: logAnalytics!.outputs.name
289304
}
@@ -313,7 +328,7 @@ module api 'api.bicep' = {
313328
otelInstrumentationGenAICaptureMessageContent: otelInstrumentationGenAICaptureMessageContent
314329
projectEndpoint: projectEndpoint
315330
searchConnectionId: searchConnectionId_final
316-
storageAccountResourceId: ai!.outputs.storageAccountId
331+
storageAccountResourceId: storageAccountResourceId_final
317332
blobContainerName: blobContainerName
318333
useAzureAISearch: useSearchService
319334
}
@@ -508,7 +523,7 @@ output AZURE_EXISTING_AGENT_ID string = agentID
508523
output AZURE_EXISTING_AIPROJECT_ENDPOINT string = projectEndpoint
509524
output ENABLE_AZURE_MONITOR_TRACING bool = enableAzureMonitorTracing
510525
output OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT bool = otelInstrumentationGenAICaptureMessageContent
511-
output STORAGE_ACCOUNT_RESOURCE_ID string = ai!.outputs.storageAccountId
526+
output STORAGE_ACCOUNT_RESOURCE_ID string = storageAccountResourceId_final
512527
output AZURE_BLOB_CONTAINER_NAME string = blobContainerName
513528

514529
// Outputs required by azd for ACA

0 commit comments

Comments
 (0)