diff --git a/docs/deploymentguide.md b/docs/deploymentguide.md index 2c4eb96f..f21b5d23 100644 --- a/docs/deploymentguide.md +++ b/docs/deploymentguide.md @@ -192,42 +192,6 @@ Edit `infra/main.bicepparam` or set environment variables: # var fabricWorkspacePreset = 'none' ``` -#### Reusing an Existing Fabric Capacity and Workspace (BYO mode) - -If you already have a Fabric capacity and workspace, set `byo` mode so the deployment skips creating new ones. The bicepparam variables are driven by environment variables, so the recommended approach is to set them with `azd env set` before running `azd up`: - -**Step 1 — Set the mode** ( The default value is `create`, so override it to `byo`): - -```bicep -// infra/main.bicepparam -var fabricCapacityPreset = readEnvironmentVariable('fabricCapacityMode', 'create') -``` - -The `fabricCapacityMode` env variable controls both capacity and workspace preset (they are tied together). Set it explicitly to use BYO mode: - -```powershell -azd env set fabricCapacityMode byo -``` - -**Step 2 — Supply the existing resource identifiers:** - -```powershell -# ARM resource ID of the existing Fabric capacity -azd env set fabricCapacityResourceId "/subscriptions//resourceGroups//providers/Microsoft.Fabric/capacities/" - -# GUID of the existing Fabric workspace (from the workspace URL or Fabric portal) -azd env set FABRIC_WORKSPACE_ID "" - -# Display name of the existing workspace (used for naming/UX; optional but recommended) -azd env set FABRIC_WORKSPACE_NAME "" -``` - -> **How to find the workspace GUID:** Open the workspace in [app.fabric.microsoft.com](https://app.fabric.microsoft.com), copy the URL. The segment after `/groups/` is the workspace GUID (e.g., `https://app.fabric.microsoft.com/groups/e9c7ed61-0cdc-4356-a239-9d49cc755fe0/...` → `e9c7ed61-0cdc-4356-a239-9d49cc755fe0`). - -> **How to find the capacity resource ID:** In Azure Portal, open the Fabric capacity resource → **Properties** → copy **Resource ID**. It follows the pattern `/subscriptions/.../providers/Microsoft.Fabric/capacities/`. - -After setting these variables, run `azd up` normally. The deployment will attach to your existing capacity and workspace instead of creating new ones. -
@@ -240,6 +204,7 @@ After setting these variables, run `azd up` normally. The deployment will attach | `useExistingVNet` | Reuse an existing VNet | `false` | | `existingVnetResourceId` | Existing VNet resource ID (when `useExistingVNet=true`) | `` | | `existingLogAnalyticsWorkspaceResourceId` | Existing Log Analytics workspace to receive PostgreSQL diagnostics. May live in another subscription within the same tenant. | `` | +| `existingAiProjectResourceId` | Existing Microsoft Foundry **project** resource ID to reuse instead of creating a new Foundry account + project. When set, `deployAiFoundry` and `deployAfProject` are auto-disabled. Read from `AZURE_EXISTING_AI_PROJECT_RESOURCE_ID`. | `` | | `vmUserName` | Jump box VM admin username | `VM_ADMIN_USERNAME` env var or `testvmuser` | | `vmAdminPassword` | Jump box VM admin password | `VM_ADMIN_PASSWORD` env var | @@ -269,19 +234,11 @@ To check and adjust quota settings, follow the [Quota Check Guide](./quota_check
Reusing Existing Resources -**Log Analytics Workspace (BYO observability):** - -By default the wrapper does not create a Log Analytics workspace or Application Insights, so the deployed Foundry application and wrapper-managed PostgreSQL Flexible Server have no telemetry sink. If you already have a centralized workspace, point the deployment at it: - -```powershell -azd env set EXISTING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID "/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/" -``` - -When set, the deployment will: -1. Route PostgreSQL diagnostic logs and metrics to your workspace (when PostgreSQL is deployed by the wrapper). -2. Create an Application Insights component in the deployment resource group, linked to your existing workspace — only when Application Insights deployment is enabled and the deployment is not creating a new Log Analytics workspace (i.e. `deployAppInsights = true` and `deployLogAnalytics = false`, which are the wrapper defaults). +You can reuse existing Azure resources instead of provisioning new ones. Refer to the dedicated guides below: -The workspace may live in a different resource group or subscription within the same tenant. The identity running `azd up` needs **`Microsoft.Insights/diagnosticSettings/write`** on the workspace itself (covered by the built-in **Log Analytics Contributor** role scoped to the workspace or its resource group — subscription-wide rights are not required). See the **Observability — Bring Your Own Log Analytics Workspace** section in the [Parameter Guide](./parameter_guide.md) for the full output reference (including App Insights values when that component is deployed) and notes on deployment-history exposure of those values. +- [Reusing an Existing Azure AI Foundry Project](./re-use-foundry-project.md) +- [Reusing an Existing Log Analytics Workspace](./re-use-log-analytics.md) +- [Reusing an Existing Fabric Capacity and Workspace](./re-use-fabric-capacity.md)
diff --git a/docs/images/azure_ai_foundry_list.png b/docs/images/azure_ai_foundry_list.png new file mode 100644 index 00000000..784bc85c Binary files /dev/null and b/docs/images/azure_ai_foundry_list.png differ diff --git a/docs/images/navigate_to_projects.png b/docs/images/navigate_to_projects.png new file mode 100644 index 00000000..11082c15 Binary files /dev/null and b/docs/images/navigate_to_projects.png differ diff --git a/docs/images/project_resource_id.png b/docs/images/project_resource_id.png new file mode 100644 index 00000000..7835ea9d Binary files /dev/null and b/docs/images/project_resource_id.png differ diff --git a/docs/images/re_use_log/logAnalytics.png b/docs/images/re_use_log/logAnalytics.png new file mode 100644 index 00000000..95402f8d Binary files /dev/null and b/docs/images/re_use_log/logAnalytics.png differ diff --git a/docs/images/re_use_log/logAnalyticsJson.png b/docs/images/re_use_log/logAnalyticsJson.png new file mode 100644 index 00000000..3a4093bf Binary files /dev/null and b/docs/images/re_use_log/logAnalyticsJson.png differ diff --git a/docs/images/re_use_log/logAnalyticsList.png b/docs/images/re_use_log/logAnalyticsList.png new file mode 100644 index 00000000..6dcf4640 Binary files /dev/null and b/docs/images/re_use_log/logAnalyticsList.png differ diff --git a/docs/parameter_guide.md b/docs/parameter_guide.md index 38f38118..c57f610d 100644 --- a/docs/parameter_guide.md +++ b/docs/parameter_guide.md @@ -14,120 +14,6 @@ This guide focuses on configuration concepts for the **AI Landing Zone**. > **Deployment flow**: This repo deploys the AI Landing Zone submodule from `submodules/ai-landing-zone/main.bicep` during the preprovision hook. The single source of truth for parameters is `infra/main.bicepparam`. -## Fabric Configuration - -### Modes: create, byo, none - -| Mode | Description | -|------|-------------| -| `create` | Provisions a new Fabric capacity (Bicep) and workspace (postprovision script) | -| `byo` | Reuses an existing Fabric capacity and workspace — no new resources created | -| `none` | Disables all Fabric automation; OneLake indexing will be skipped | - -Both capacity and workspace modes are controlled by the same `fabricCapacityMode` environment variable (they are tied together in `infra/main.bicepparam`). - -### Setting Mode via azd env - -The recommended way to configure Fabric mode is with `azd env set` — these values are read directly by `infra/main.bicepparam` at provision time: - -```powershell -# Choose one: -azd env set fabricCapacityMode create # create new capacity + workspace (default if not set) -azd env set fabricCapacityMode byo # reuse existing capacity + workspace -azd env set fabricCapacityMode none # disable all Fabric automation -``` - -### Reusing Existing Fabric Resources (BYO) - -When `fabricCapacityMode` is `byo`, supply the identifiers of your existing resources: - -```powershell -# ARM resource ID of the existing Fabric capacity -azd env set fabricCapacityResourceId "/subscriptions//resourceGroups//providers/Microsoft.Fabric/capacities/" - -# GUID of the existing Fabric workspace (from the workspace URL) -azd env set FABRIC_WORKSPACE_ID "" - -# Display name of the existing workspace (optional, used for naming/UX) -azd env set FABRIC_WORKSPACE_NAME "" -``` - -> **How to find the workspace GUID:** Open the workspace in [app.fabric.microsoft.com](https://app.fabric.microsoft.com). The URL segment after `/groups/` is the GUID (e.g., `https://app.fabric.microsoft.com/groups/e9c7ed61-0cdc-4356-a239-9d49cc755fe0/...`). -> -> **How to find the capacity resource ID:** Azure Portal → Fabric capacity resource → **Properties** → **Resource ID**. - -You can also set these directly in `infra/main.bicepparam` if you prefer source-controlled values: - -```bicep -// infra/main.bicepparam -var fabricCapacityPreset = 'byo' -param fabricCapacityResourceId = '/subscriptions//resourceGroups//providers/Microsoft.Fabric/capacities/' -param fabricWorkspaceId = '' -param fabricWorkspaceName = '' -``` - -> **Note:** Values set via `azd env set` take precedence over hardcoded bicepparam values because `readEnvironmentVariable(...)` is evaluated at deploy time. - -### Creating New Fabric Resources - -When `fabricCapacityMode` is `create`, you must provide at least one admin principal: - -```bicep -// infra/main.bicepparam -param fabricCapacityAdmins = ['user@contoso.com'] -param fabricCapacitySku = 'F2' // adjust SKU as needed -``` - -> **Permission requirement:** The identity running `azd` must have the **Fabric Administrator** role (or Power BI tenant admin) to call the workspace admin APIs used during postprovision. - ---- - -## Observability — Bring Your Own Log Analytics Workspace - -By default the wrapper sets `deployLogAnalytics = false`, so the AI Landing Zone does not create a new Log Analytics workspace and Application Insights is not provisioned. If you already have a centralized Log Analytics workspace (for example one shared across the platform), you can wire the deployed Foundry application and the wrapper-managed PostgreSQL Flexible Server to it. - -### How it works - -When you set `existingLogAnalyticsWorkspaceResourceId`: - -1. An **Application Insights** component is created in the deployment resource group and linked to your existing workspace via `WorkspaceResourceId` — **only when `deployAppInsights = true` and `deployLogAnalytics = false`** (the wrapper defaults). Its name follows the same `appInsightsName` convention (`appi-`). -2. **PostgreSQL Flexible Server** diagnostic settings (all logs + AllMetrics) are routed to your workspace (only when PostgreSQL is deployed by the wrapper). -3. The connection string and instrumentation key are exposed as deployment outputs (when the Application Insights component is created) so post-provision automation (or your application configuration) can pick them up. - -> **Note:** This is wrapper-side wiring. The upstream AI Landing Zone submodule does not natively support a BYO Log Analytics workspace, so leave `deployLogAnalytics = false` and `deployAppInsights = true` (the defaults) when using BYO so the LAZ does not create its own workspace + Application Insights pair. - -### Setting it via azd env - -```powershell -azd env set EXISTING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID "/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/" -``` - -Or set it directly in `infra/main.bicepparam`: - -```bicep -param existingLogAnalyticsWorkspaceResourceId = '/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/' -``` - -### Outputs - -| Output | Description | -|--------|-------------| -| `existingLogAnalyticsWorkspaceResourceIdOut` | Echo of the supplied workspace resource ID | -| `byoApplicationInsightsResourceId` | Resource ID of the App Insights component created against the BYO workspace | -| `byoApplicationInsightsName` | Name of the App Insights component | -| `byoApplicationInsightsConnectionString` | Connection string for app instrumentation | -| `byoApplicationInsightsInstrumentationKey` | Instrumentation key for legacy SDKs | - -> **Sensitive outputs:** The connection string and instrumentation key are bootstrap credentials for sending telemetry to your Application Insights resource. They are emitted as deployment outputs so post-provision scripts and `azd` env can wire them into application configuration. Anyone with read access to the deployment history (subscription/RG `Microsoft.Resources/deployments/read`) can retrieve these values — keep that access scoped appropriately. - -### Permissions - -The identity running the deployment needs permission to attach diagnostic settings to the workspace and to create the Application Insights component: - -- **`Microsoft.Insights/diagnosticSettings/write`** on the BYO Log Analytics workspace (or its resource group). The built-in **Log Analytics Contributor** role on the workspace (or its RG) covers this — there is no need to grant subscription-wide rights. -- **`Microsoft.Insights/components/write`** on the deployment resource group (covered by **Contributor** on the deployment RG, which the deployment identity already needs to provision the rest of the stack). -- The PostgreSQL Flexible Server that emits diagnostics is wrapper-managed in the deployment RG, so no additional cross-resource permissions are required. - --- ## Table of Contents diff --git a/docs/re-use-fabric-capacity.md b/docs/re-use-fabric-capacity.md new file mode 100644 index 00000000..a29e0bc9 --- /dev/null +++ b/docs/re-use-fabric-capacity.md @@ -0,0 +1,43 @@ +[← Back to *DEPLOYMENT* guide](/docs/deploymentguide.md#deployment-steps) + +# Reusing an Existing Fabric Capacity and Workspace (BYO mode) + +If you already have a Fabric capacity and workspace, set `byo` mode so the deployment skips creating new ones. The bicepparam variables are driven by environment variables, so the recommended approach is to set them with `azd env set` before running `azd up`: + +## Step 1 — Set the mode + +(The default value is `create`, so override it to `byo`): + +```bicep +// infra/main.bicepparam +var fabricCapacityPreset = readEnvironmentVariable('fabricCapacityMode', 'create') +``` + +The `fabricCapacityMode` env variable controls both capacity and workspace preset (they are tied together). Set it explicitly to use BYO mode: + +```powershell +azd env set fabricCapacityMode byo +``` + +## Step 2 — Supply the existing resource identifiers + +```powershell +# ARM resource ID of the existing Fabric capacity +azd env set fabricCapacityResourceId "/subscriptions//resourceGroups//providers/Microsoft.Fabric/capacities/" + +# GUID of the existing Fabric workspace (from the workspace URL or Fabric portal) +azd env set FABRIC_WORKSPACE_ID "" + +# Display name of the existing workspace (used for naming/UX; optional but recommended) +azd env set FABRIC_WORKSPACE_NAME "" +``` + +> **How to find the workspace GUID:** Open the workspace in [app.fabric.microsoft.com](https://app.fabric.microsoft.com), copy the URL. The segment after `/groups/` is the workspace GUID (e.g., `https://app.fabric.microsoft.com/groups/e9c7ed61-0cdc-4356-a239-9d49cc755fe0/...` → `e9c7ed61-0cdc-4356-a239-9d49cc755fe0`). + +> **How to find the capacity resource ID:** In Azure Portal, open the Fabric capacity resource → **Properties** → copy **Resource ID**. It follows the pattern `/subscriptions/.../providers/Microsoft.Fabric/capacities/`. + +After setting these variables, run `azd up` normally. The deployment will attach to your existing capacity and workspace instead of creating new ones. + +--- + +[← Back to *DEPLOYMENT* guide](/docs/deploymentguide.md#deployment-steps) diff --git a/docs/re-use-foundry-project.md b/docs/re-use-foundry-project.md new file mode 100644 index 00000000..adb6032a --- /dev/null +++ b/docs/re-use-foundry-project.md @@ -0,0 +1,60 @@ +[← Back to *DEPLOYMENT* guide](/docs/deploymentguide.md#deployment-steps) + +# Reusing an Existing Azure AI Foundry Project + +To configure your environment to use an existing Azure AI Foundry Project, follow these steps: + +--- + +### 1. Go to Azure Portal + +Go to https://portal.azure.com + +### 2. Search for Azure AI Foundry + +In the search bar at the top, type "Azure AI Foundry" and click on it. Then select the Foundry service instance where your project exists. + +![alt text](../docs/images/azure_ai_foundry_list.png) + +### 3. Navigate to Projects under Resource Management + +On the left sidebar of the Foundry service blade: + +- Expand the **Resource Management** section +- Click on **Projects** (this refers to the active Foundry project tied to the service) + +### 4. Click on the Project + +From the Projects view: Click on the project name to open its details. + +> **Note:** You will see only one project listed here, as each Foundry service maps to a single project in this accelerator. + +![alt text](../docs/images/navigate_to_projects.png) + +### 5. Copy Resource ID + +In the left-hand menu of the project blade: + +- Click on **Properties** under **Resource Management** +- Locate the **Resource ID** field +- Click on the copy icon next to the Resource ID value + +![alt text](../docs/images/project_resource_id.png) + +### 6. Set the Foundry Project Resource ID in Your Environment + +Run the following command in your terminal: + +```bash +azd env set AZURE_EXISTING_AI_PROJECT_RESOURCE_ID '' +``` + +Replace `` with the value obtained from Step 5. + +### 7. Continue Deployment + +Proceed with the next steps in the [deployment guide](/docs/deploymentguide.md#deployment-steps). + +--- + +[← Back to *DEPLOYMENT* guide](/docs/deploymentguide.md#deployment-steps) diff --git a/docs/re-use-log-analytics.md b/docs/re-use-log-analytics.md new file mode 100644 index 00000000..bb38928f --- /dev/null +++ b/docs/re-use-log-analytics.md @@ -0,0 +1,45 @@ +[← Back to *DEPLOYMENT* guide](/docs/deploymentguide.md#deployment-steps) + +# Reusing an Existing Log Analytics Workspace + +To configure your environment to use an existing Log Analytics Workspace, follow these steps: + +--- + +### 1. Go to Azure Portal + +Go to https://portal.azure.com + +### 2. Search for Log Analytics + +In the search bar at the top, type "Log Analytics workspaces" and click on it, then click on the workspace you want to use. + +![alt text](../docs/images/re_use_log/logAnalyticsList.png) + +### 3. Copy Resource ID + +In the **Overview** pane, click on **JSON View**. + +![alt text](../docs/images/re_use_log/logAnalytics.png) + +Copy the **Resource ID** that is your Workspace ID. + +![alt text](../docs/images/re_use_log/logAnalyticsJson.png) + +### 4. Set the Workspace ID in Your Environment + +Run the following command in your terminal: + +```bash +azd env set EXISTING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID '' +``` + +Replace `` with the value obtained from Step 3. + +### 5. Continue Deployment + +Proceed with the next steps in the [deployment guide](/docs/deploymentguide.md#deployment-steps). + +--- + +[← Back to *DEPLOYMENT* guide](/docs/deploymentguide.md#deployment-steps) diff --git a/infra/main.bicep b/infra/main.bicep index c6ed8aca..0de11617 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -111,6 +111,9 @@ param aiFoundryStorageAccountResourceId string = '' param aiFoundryCosmosDBAccountResourceId string = '' param keyVaultResourceId string = '' +@description('Optional. Full ARM resource ID of an existing Azure AI Foundry project to reuse. When provided, the wrapper and AI Landing Zone submodule will skip creating a new AI Foundry account/project, and downstream automation (RBAC, OneLake indexing, AI Foundry connections) will target the existing project. Cross-subscription resource IDs are supported. Format: /subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.CognitiveServices/accounts/{account}/projects/{project}.') +param existingAiProjectResourceId string = '' + @description('Optional. Full ARM resource ID of an existing Log Analytics workspace to use for observability of the deployed Foundry application and wrapper-managed PostgreSQL. When provided, an Application Insights component is created in the deployment resource group and linked to this workspace, and diagnostic settings on the wrapper-managed PostgreSQL flexible server are routed to it. Leave empty to skip BYO behavior. Format: /subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.OperationalInsights/workspaces/{name}.') param existingLogAnalyticsWorkspaceResourceId string = '' @@ -524,10 +527,33 @@ var effectiveAiSearchResourceId = !empty(aiSearchResourceId) var effectiveStorageAccountResourceId = resourceId('Microsoft.Storage/storageAccounts', storageAccountName) +// ---------------------------------------------------------------------- +// BYO existing AI Foundry Project parsing. +// When existingAiProjectResourceId is provided, parse it into its +// subscription / resource group / account / project segments so downstream +// automation can target the existing project instead of a wrapper-created +// one. Cross-subscription resource IDs are supported. +// ---------------------------------------------------------------------- +var byoAiProjectEnabled = !empty(existingAiProjectResourceId) +var byoAiProjectIdSegments = split(byoAiProjectEnabled ? existingAiProjectResourceId : '', '/') +var byoAiProjectSubscriptionId = length(byoAiProjectIdSegments) >= 3 ? byoAiProjectIdSegments[2] : '' +var byoAiProjectResourceGroupName = length(byoAiProjectIdSegments) >= 5 ? byoAiProjectIdSegments[4] : '' +var byoAiFoundryAccountName = length(byoAiProjectIdSegments) >= 9 ? byoAiProjectIdSegments[8] : '' +var byoAiFoundryProjectName = length(byoAiProjectIdSegments) >= 11 ? byoAiProjectIdSegments[10] : '' +var effectiveAiFoundryAccountName = byoAiProjectEnabled ? byoAiFoundryAccountName : aiFoundryAccountName +var effectiveAiFoundryProjectName = byoAiProjectEnabled ? byoAiFoundryProjectName : aiFoundryProjectName +var effectiveAiFoundryResourceGroup = byoAiProjectEnabled ? byoAiProjectResourceGroupName : resourceGroup().name +var effectiveAiFoundrySubscriptionId = byoAiProjectEnabled ? byoAiProjectSubscriptionId : subscription().subscriptionId + output virtualNetworkResourceId string = effectiveVnetResourceId output keyVaultResourceId string = effectiveKeyVaultResourceId output storageAccountResourceId string = effectiveStorageAccountResourceId -output aiFoundryProjectName string = aiFoundryProjectName +output aiFoundryProjectName string = effectiveAiFoundryProjectName +output aiFoundryAccountName string = effectiveAiFoundryAccountName +output aiFoundryResourceGroup string = effectiveAiFoundryResourceGroup +output aiFoundrySubscriptionId string = effectiveAiFoundrySubscriptionId +output existingAiProjectResourceIdOut string = existingAiProjectResourceId +output useExistingAiProject bool = byoAiProjectEnabled output aiSearchResourceId string = effectiveAiSearchResourceId output aiSearchName string = searchServiceName output aiSearchAdditionalAccessObjectIds array = aiSearchAdditionalAccessObjectIds diff --git a/infra/main.bicepparam b/infra/main.bicepparam index 9f8ac0e9..1e726e11 100644 --- a/infra/main.bicepparam +++ b/infra/main.bicepparam @@ -23,6 +23,16 @@ param keyVaultResourceId = '' param useExistingVNet = false param existingVnetResourceId = readEnvironmentVariable('EXISTING_VNET_RESOURCE_ID', '') +// BYO existing Azure AI Foundry Project (cross-subscription supported). +// When AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is set, the wrapper and the +// AI Landing Zone submodule will skip creating a new AI Foundry account and +// project; downstream automation (RBAC, OneLake indexing, AI Foundry +// connections) will target the existing project instead. +// Format: /subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.CognitiveServices/accounts/{aiFoundryAccount}/projects/{aiFoundryProject} +var existingAiProjectResourceIdVar = readEnvironmentVariable('AZURE_EXISTING_AI_PROJECT_RESOURCE_ID', '') +param existingAiProjectResourceId = existingAiProjectResourceIdVar +var useExistingAiProjectVar = !empty(existingAiProjectResourceId) + // BYO Log Analytics Workspace for observability of the deployed Foundry // application and wrapper-managed PostgreSQL resources. // When provided, diagnostic settings on the wrapper-managed PostgreSQL @@ -91,7 +101,9 @@ param postgreSqlStorageSizeGB = 32 // ======================================== param deployGroundingWithBing = false -param deployAiFoundry = true +// When AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is set, skip creating a new +// AI Foundry account/project (BYO mode). +param deployAiFoundry = !useExistingAiProjectVar param deployAiFoundrySubnet = false param deployAppConfig = true param deployKeyVault = true @@ -110,7 +122,9 @@ param deployNsgs = true param sideBySideDeploy = readEnvironmentVariable('SIDE_BY_SIDE', 'true') == 'true' param deploySoftware = false param deployApim = false -param deployAfProject = true +// When AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is set, skip creating a new +// AI Foundry project (BYO mode). +param deployAfProject = !useExistingAiProjectVar param deployAAfAgentSvc = false param enableAgenticRetrieval = readEnvironmentVariable('ENABLE_AGENTIC_RETRIEVAL', 'false') == 'true' diff --git a/scripts/preprovision-integrated.ps1 b/scripts/preprovision-integrated.ps1 index 2b6d2099..03f1c0fc 100644 --- a/scripts/preprovision-integrated.ps1 +++ b/scripts/preprovision-integrated.ps1 @@ -449,27 +449,64 @@ if ([string]::IsNullOrWhiteSpace($aiSearchName)) { try { $aiSearchName = (az search service list --resource-group $ResourceGroup --query "[0].name" -o tsv 2>$null).Trim() } catch { } } +# BYO existing AI Foundry project: when AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is +# set (and surfaced through the bicepparam as existingAiProjectResourceId), parse +# its segments and use them for the downstream azd env values so postprovision +# automation targets the existing account/project instead of attempting RG +# discovery in this deployment's resource group. +$existingAiProjectResourceId = $null +try { $existingAiProjectResourceId = [string]$parentJson.parameters.existingAiProjectResourceId.value } catch { } +if ([string]::IsNullOrWhiteSpace($existingAiProjectResourceId)) { + $existingAiProjectResourceId = $env:AZURE_EXISTING_AI_PROJECT_RESOURCE_ID +} + $aiFoundryName = $null -try { $aiFoundryName = [string]$parentJson.parameters.aiFoundryAccountName.value } catch { } +$aiFoundryProjectName = $null +$aiFoundryResourceGroupForEnv = $ResourceGroup +$aiFoundrySubscriptionForEnv = $SubscriptionId + +if (-not [string]::IsNullOrWhiteSpace($existingAiProjectResourceId)) { + Write-Host " [i] BYO AI Foundry project detected: $existingAiProjectResourceId" -ForegroundColor Cyan + $segments = $existingAiProjectResourceId.Trim('/').Split('/') + # Expected: subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.CognitiveServices/accounts/{account}/projects/{project} + if ($segments.Length -ge 10 -and $segments[0] -ieq 'subscriptions' -and $segments[2] -ieq 'resourceGroups' -and $segments[6] -ieq 'accounts' -and $segments[8] -ieq 'projects') { + $aiFoundrySubscriptionForEnv = $segments[1] + $aiFoundryResourceGroupForEnv = $segments[3] + $aiFoundryName = $segments[7] + $aiFoundryProjectName = $segments[9] + Write-Host " Account: $aiFoundryName" -ForegroundColor Green + Write-Host " Project: $aiFoundryProjectName" -ForegroundColor Green + Write-Host " ResourceGrp: $aiFoundryResourceGroupForEnv" -ForegroundColor Green + Write-Host " Subscription: $aiFoundrySubscriptionForEnv" -ForegroundColor Green + } else { + Write-Host " [!] AZURE_EXISTING_AI_PROJECT_RESOURCE_ID is set but the resource ID format is not recognized. Falling back to discovery." -ForegroundColor Yellow + $existingAiProjectResourceId = $null + } +} + if ([string]::IsNullOrWhiteSpace($aiFoundryName)) { - try { - $aiFoundryName = (az cognitiveservices account list --resource-group $ResourceGroup --query "[?kind=='AIServices']|[0].name" -o tsv 2>$null).Trim() - } catch { } + try { $aiFoundryName = [string]$parentJson.parameters.aiFoundryAccountName.value } catch { } + if ([string]::IsNullOrWhiteSpace($aiFoundryName)) { + try { + $aiFoundryName = (az cognitiveservices account list --resource-group $ResourceGroup --query "[?kind=='AIServices']|[0].name" -o tsv 2>$null).Trim() + } catch { } + } } -$aiFoundryProjectName = $null -try { $aiFoundryProjectName = [string]$parentJson.parameters.aiFoundryProjectName.value } catch { } -if ([string]::IsNullOrWhiteSpace($aiFoundryProjectName) -and -not [string]::IsNullOrWhiteSpace($aiFoundryName)) { - try { - $projectCandidatesRaw = az resource list --resource-group $ResourceGroup --resource-type "Microsoft.CognitiveServices/accounts/projects" --query "[?contains(id, '/accounts/$aiFoundryName/')].name" -o tsv 2>$null - if ($projectCandidatesRaw) { - [string[]]$projectCandidates = ($projectCandidatesRaw -split "\r?\n") | Where-Object { $_ -and $_.Trim() } | ForEach-Object { $_.Trim() } - if ($projectCandidates.Length -ge 1) { - $aiFoundryProjectName = $projectCandidates[0] +if ([string]::IsNullOrWhiteSpace($aiFoundryProjectName)) { + try { $aiFoundryProjectName = [string]$parentJson.parameters.aiFoundryProjectName.value } catch { } + if ([string]::IsNullOrWhiteSpace($aiFoundryProjectName) -and -not [string]::IsNullOrWhiteSpace($aiFoundryName)) { + try { + $projectCandidatesRaw = az resource list --resource-group $aiFoundryResourceGroupForEnv --subscription $aiFoundrySubscriptionForEnv --resource-type "Microsoft.CognitiveServices/accounts/projects" --query "[?contains(id, '/accounts/$aiFoundryName/')].name" -o tsv 2>$null + if ($projectCandidatesRaw) { + [string[]]$projectCandidates = ($projectCandidatesRaw -split "\r?\n") | Where-Object { $_ -and $_.Trim() } | ForEach-Object { $_.Trim() } + if ($projectCandidates.Length -ge 1) { + $aiFoundryProjectName = $projectCandidates[0] + } } + } catch { + # Ignore discovery failures and continue. } - } catch { - # Ignore discovery failures and continue. } } @@ -484,8 +521,14 @@ Set-AzdEnvValue -Name 'aiSearchResourceId' -Value $aiSearchResourceId Set-AzdEnvValue -Name 'aiSearchResourceGroup' -Value $ResourceGroup Set-AzdEnvValue -Name 'aiSearchSubscriptionId' -Value $SubscriptionId Set-AzdEnvValue -Name 'aiFoundryName' -Value $aiFoundryName -Set-AzdEnvValue -Name 'aiFoundryResourceGroup' -Value $ResourceGroup +Set-AzdEnvValue -Name 'aiFoundryResourceGroup' -Value $aiFoundryResourceGroupForEnv +Set-AzdEnvValue -Name 'aiFoundrySubscriptionId' -Value $aiFoundrySubscriptionForEnv Set-AzdEnvValue -Name 'aiFoundryProjectName' -Value $aiFoundryProjectName +if (-not [string]::IsNullOrWhiteSpace($existingAiProjectResourceId)) { + Set-AzdEnvValue -Name 'AZURE_EXISTING_AI_PROJECT_RESOURCE_ID' -Value $existingAiProjectResourceId + Set-AzdEnvValue -Name 'existingAiProjectResourceId' -Value $existingAiProjectResourceId + Set-AzdEnvValue -Name 'useExistingAiProject' -Value 'true' +} Write-Host ""