From ad4cbd903691c635708f252d03668829dd51b4c0 Mon Sep 17 00:00:00 2001 From: NirajC3-Microsoft Date: Wed, 5 Aug 2026 19:40:37 +0530 Subject: [PATCH] chore: update build_and_push script to get values from RG, update post_deploy script to get missing values --- .../post-provision/Build-And-Push-Images.ps1 | 102 +++++++++++++--- .../post-provision/build_and_push_images.sh | 110 +++++++++++++----- infra/scripts/post-provision/post_deploy.ps1 | 18 +++ infra/scripts/post-provision/post_deploy.sh | 18 +++ 4 files changed, 203 insertions(+), 45 deletions(-) diff --git a/infra/scripts/post-provision/Build-And-Push-Images.ps1 b/infra/scripts/post-provision/Build-And-Push-Images.ps1 index d6d57dcba..d87d423fa 100644 --- a/infra/scripts/post-provision/Build-And-Push-Images.ps1 +++ b/infra/scripts/post-provision/Build-And-Push-Images.ps1 @@ -18,6 +18,11 @@ - the MCP Container App image - the frontend Web App container image and DOCKER_REGISTRY_SERVER_URL +.PARAMETER ResourceGroup + Optional. When provided, the script queries Azure directly to discover + resources (ACR, Container Apps, Web App) in the specified resource group + instead of reading from azd environment / .azure files. + .PARAMETER BuildMode Optional. `remote` (default) or `local`. Overrides the AZURE_ENV_BUILD_MODE environment variable when provided. @@ -34,12 +39,18 @@ # Remote build (no Docker needed on the client machine) ./infra/scripts/post-provision/Build-And-Push-Images.ps1 +.EXAMPLE + # Build using a specific resource group (no .azure file needed) + ./infra/scripts/post-provision/Build-And-Push-Images.ps1 -ResourceGroup "my-rg-name" + .EXAMPLE # Local build using Docker Desktop ./infra/scripts/post-provision/Build-And-Push-Images.ps1 -BuildMode local -ImageTag dev #> [CmdletBinding()] param( + [string]$ResourceGroup, + [ValidateSet('local', 'remote')] [string]$BuildMode, @@ -94,25 +105,80 @@ if ($Skip -or ([Environment]::GetEnvironmentVariable('AZURE_ENV_SKIP_IMAGE_BUILD } # --- Read configuration ----------------------------------------------------- -Write-Section 'Reading azd environment values' -$azdEnv = Get-AzdEnvValues - -$acrName = Get-EnvOrAzd -Name 'AZURE_CONTAINER_REGISTRY_NAME' -AzdEnv $azdEnv -$acrEndpoint = Get-EnvOrAzd -Name 'AZURE_CONTAINER_REGISTRY_ENDPOINT' -AzdEnv $azdEnv -$resourceGroup = Get-EnvOrAzd -Name 'AZURE_RESOURCE_GROUP' -AzdEnv $azdEnv -$backendCa = Get-EnvOrAzd -Name 'BACKEND_CONTAINER_APP_NAME' -AzdEnv $azdEnv -$mcpCa = Get-EnvOrAzd -Name 'MCP_CONTAINER_APP_NAME' -AzdEnv $azdEnv -$frontendApp = Get-EnvOrAzd -Name 'FRONTEND_WEB_APP_NAME' -AzdEnv $azdEnv -$backendImage = Get-EnvOrAzd -Name 'BACKEND_IMAGE_NAME' -AzdEnv $azdEnv -Default 'macaebackend' -$frontendImage = Get-EnvOrAzd -Name 'FRONTEND_IMAGE_NAME' -AzdEnv $azdEnv -Default 'macaefrontend' -$mcpImage = Get-EnvOrAzd -Name 'MCP_IMAGE_NAME' -AzdEnv $azdEnv -Default 'macaemcp' -$frontendPort = Get-EnvOrAzd -Name 'FRONTEND_WEBSITES_PORT' -AzdEnv $azdEnv -Default '3000' - -if (-not $BuildMode) { - $BuildMode = Get-EnvOrAzd -Name 'AZURE_ENV_BUILD_MODE' -AzdEnv $azdEnv -Default 'remote' +if (-not [string]::IsNullOrWhiteSpace($ResourceGroup)) { + Write-Section "Discovering resources from resource group: $ResourceGroup" + + if (-not (Get-Command az -ErrorAction SilentlyContinue)) { + throw "'az' CLI is required when specifying the -ResourceGroup parameter." + } + + $resourceGroup = $ResourceGroup + + # Discover ACR + $acrName = (az acr list --resource-group $resourceGroup --query "[0].name" -o tsv 2>$null) + $acrEndpoint = (az acr list --resource-group $resourceGroup --query "[0].loginServer" -o tsv 2>$null) + + # Discover Container Apps + $caList = (az containerapp list --resource-group $resourceGroup --query "[].name" -o tsv 2>$null) + $backendCa = $null + $mcpCa = $null + if ($caList) { + foreach ($caName in ($caList -split "`n")) { + $caName = $caName.Trim() + if ([string]::IsNullOrWhiteSpace($caName)) { continue } + $caLower = $caName.ToLower() + if ($caLower -like '*mcp*') { + $mcpCa = $caName + } + else { + $backendCa = $caName + } + } + } + + # Discover Frontend Web App + $frontendApp = (az webapp list --resource-group $resourceGroup --query "[0].name" -o tsv 2>$null) + + # Use defaults or env overrides for image names + $backendImage = if ([Environment]::GetEnvironmentVariable('BACKEND_IMAGE_NAME')) { [Environment]::GetEnvironmentVariable('BACKEND_IMAGE_NAME') } else { 'macaebackend' } + $frontendImage = if ([Environment]::GetEnvironmentVariable('FRONTEND_IMAGE_NAME')) { [Environment]::GetEnvironmentVariable('FRONTEND_IMAGE_NAME') } else { 'macaefrontend' } + $mcpImage = if ([Environment]::GetEnvironmentVariable('MCP_IMAGE_NAME')) { [Environment]::GetEnvironmentVariable('MCP_IMAGE_NAME') } else { 'macaemcp' } + $frontendPort = if ([Environment]::GetEnvironmentVariable('FRONTEND_WEBSITES_PORT')) { [Environment]::GetEnvironmentVariable('FRONTEND_WEBSITES_PORT') } else { '3000' } + + if (-not $BuildMode) { + $BuildMode = if ([Environment]::GetEnvironmentVariable('AZURE_ENV_BUILD_MODE')) { [Environment]::GetEnvironmentVariable('AZURE_ENV_BUILD_MODE') } else { 'remote' } + } + if (-not $ImageTag) { + $ImageTag = if ([Environment]::GetEnvironmentVariable('AZURE_ENV_IMAGE_TAG')) { [Environment]::GetEnvironmentVariable('AZURE_ENV_IMAGE_TAG') } else { 'latest' } + } + + Write-Host "Discovered resources:" + Write-Host " ACR: $acrName ($acrEndpoint)" + Write-Host " Backend CA: $backendCa" + Write-Host " MCP CA: $mcpCa" + Write-Host " Frontend App: $frontendApp" } -if (-not $ImageTag) { - $ImageTag = Get-EnvOrAzd -Name 'AZURE_ENV_IMAGE_TAG' -AzdEnv $azdEnv -Default 'latest' +else { + Write-Section 'Reading azd environment values' + $azdEnv = Get-AzdEnvValues + + $acrName = Get-EnvOrAzd -Name 'AZURE_CONTAINER_REGISTRY_NAME' -AzdEnv $azdEnv + $acrEndpoint = Get-EnvOrAzd -Name 'AZURE_CONTAINER_REGISTRY_ENDPOINT' -AzdEnv $azdEnv + $resourceGroup = Get-EnvOrAzd -Name 'AZURE_RESOURCE_GROUP' -AzdEnv $azdEnv + $backendCa = Get-EnvOrAzd -Name 'BACKEND_CONTAINER_APP_NAME' -AzdEnv $azdEnv + $mcpCa = Get-EnvOrAzd -Name 'MCP_CONTAINER_APP_NAME' -AzdEnv $azdEnv + $frontendApp = Get-EnvOrAzd -Name 'FRONTEND_WEB_APP_NAME' -AzdEnv $azdEnv + $backendImage = Get-EnvOrAzd -Name 'BACKEND_IMAGE_NAME' -AzdEnv $azdEnv -Default 'macaebackend' + $frontendImage = Get-EnvOrAzd -Name 'FRONTEND_IMAGE_NAME' -AzdEnv $azdEnv -Default 'macaefrontend' + $mcpImage = Get-EnvOrAzd -Name 'MCP_IMAGE_NAME' -AzdEnv $azdEnv -Default 'macaemcp' + $frontendPort = Get-EnvOrAzd -Name 'FRONTEND_WEBSITES_PORT' -AzdEnv $azdEnv -Default '3000' + + if (-not $BuildMode) { + $BuildMode = Get-EnvOrAzd -Name 'AZURE_ENV_BUILD_MODE' -AzdEnv $azdEnv -Default 'remote' + } + if (-not $ImageTag) { + $ImageTag = Get-EnvOrAzd -Name 'AZURE_ENV_IMAGE_TAG' -AzdEnv $azdEnv -Default 'latest' + } } foreach ($pair in @( diff --git a/infra/scripts/post-provision/build_and_push_images.sh b/infra/scripts/post-provision/build_and_push_images.sh index 6546ae92a..ee4700857 100644 --- a/infra/scripts/post-provision/build_and_push_images.sh +++ b/infra/scripts/post-provision/build_and_push_images.sh @@ -7,6 +7,13 @@ # Intended to run as an `azd` postprovision hook. Reads provisioning outputs # via `azd env get-values`. # +# Usage: +# bash build_and_push_images.sh [RESOURCE_GROUP_NAME] +# +# If RESOURCE_GROUP_NAME is provided, the script queries Azure directly to +# discover resources (ACR, Container Apps, Web App) in that RG. +# If omitted, it reads values from `azd env get-values` / environment vars. +# # Environment variables (all optional): # AZURE_ENV_BUILD_MODE remote | local (default: remote) # AZURE_ENV_IMAGE_TAG tag applied to images (default: latest) @@ -37,35 +44,84 @@ if [ "${AZURE_ENV_SKIP_IMAGE_BUILD:-}" = "true" ]; then exit 0 fi -section "Reading azd environment values" - -# Load azd outputs into the current shell without overriding vars already set. -if command -v azd >/dev/null 2>&1; then - while IFS='=' read -r key value; do - [ -z "${key}" ] && continue - # Strip surrounding quotes - value="${value%\"}" - value="${value#\"}" - if [ -z "${!key:-}" ]; then - export "${key}=${value}" +# --- Determine configuration source ----------------------------------------- +ARG_RESOURCE_GROUP="${1:-}" + +if [ -n "${ARG_RESOURCE_GROUP}" ]; then + section "Discovering resources from resource group: ${ARG_RESOURCE_GROUP}" + + if ! command -v az >/dev/null 2>&1; then + echo "ERROR: 'az' CLI is required when specifying a resource group argument." >&2 + exit 1 + fi + + RESOURCE_GROUP="${ARG_RESOURCE_GROUP}" + + # Discover ACR (tr -d '\r' strips Windows carriage returns in Git Bash) + ACR_NAME="$(az acr list --resource-group "${RESOURCE_GROUP}" --query "[0].name" -o tsv 2>/dev/null | tr -d '\r' || true)" + ACR_ENDPOINT="$(az acr list --resource-group "${RESOURCE_GROUP}" --query "[0].loginServer" -o tsv 2>/dev/null | tr -d '\r' || true)" + + # Discover Container Apps + CA_LIST="$(az containerapp list --resource-group "${RESOURCE_GROUP}" --query "[].name" -o tsv 2>/dev/null | tr -d '\r' || true)" + BACKEND_CA="" + MCP_CA="" + while IFS= read -r ca_name; do + [ -z "${ca_name}" ] && continue + ca_lower="$(echo "${ca_name}" | tr '[:upper:]' '[:lower:]')" + if [[ "${ca_lower}" == *"mcp"* ]]; then + MCP_CA="${ca_name}" + else + BACKEND_CA="${ca_name}" fi - done < <(azd env get-values 2>/dev/null || true) + done <<< "${CA_LIST}" + + # Discover Frontend Web App + FRONTEND_APP="$(az webapp list --resource-group "${RESOURCE_GROUP}" --query "[0].name" -o tsv 2>/dev/null | tr -d '\r' || true)" + + # Use defaults or env overrides for image names + BACKEND_IMAGE="${BACKEND_IMAGE_NAME:-macaebackend}" + FRONTEND_IMAGE="${FRONTEND_IMAGE_NAME:-macaefrontend}" + MCP_IMAGE="${MCP_IMAGE_NAME:-macaemcp}" + FRONTEND_PORT="${FRONTEND_WEBSITES_PORT:-3000}" + BUILD_MODE="${AZURE_ENV_BUILD_MODE:-remote}" + IMAGE_TAG="${AZURE_ENV_IMAGE_TAG:-latest}" + + echo "Discovered resources:" + echo " ACR: ${ACR_NAME:-} (${ACR_ENDPOINT:-})" + echo " Backend CA: ${BACKEND_CA:-}" + echo " MCP CA: ${MCP_CA:-}" + echo " Frontend App: ${FRONTEND_APP:-}" else - echo "WARN: 'azd' not found on PATH; relying on environment variables only." >&2 -fi + section "Reading azd environment values" + + # Load azd outputs into the current shell without overriding vars already set. + if command -v azd >/dev/null 2>&1; then + while IFS='=' read -r key value; do + [ -z "${key}" ] && continue + # Strip surrounding quotes + value="${value%\"}" + value="${value#\"}" + if [ -z "${!key:-}" ]; then + export "${key}=${value}" + fi + done < <(azd env get-values 2>/dev/null | tr -d '\r' || true) + else + echo "WARN: 'azd' not found on PATH; relying on environment variables only." >&2 + fi -ACR_NAME="${AZURE_CONTAINER_REGISTRY_NAME:-}" -ACR_ENDPOINT="${AZURE_CONTAINER_REGISTRY_ENDPOINT:-}" -RESOURCE_GROUP="${AZURE_RESOURCE_GROUP:-}" -BACKEND_CA="${BACKEND_CONTAINER_APP_NAME:-}" -MCP_CA="${MCP_CONTAINER_APP_NAME:-}" -FRONTEND_APP="${FRONTEND_WEB_APP_NAME:-}" -BACKEND_IMAGE="${BACKEND_IMAGE_NAME:-macaebackend}" -FRONTEND_IMAGE="${FRONTEND_IMAGE_NAME:-macaefrontend}" -MCP_IMAGE="${MCP_IMAGE_NAME:-macaemcp}" -FRONTEND_PORT="${FRONTEND_WEBSITES_PORT:-3000}" -BUILD_MODE="${AZURE_ENV_BUILD_MODE:-remote}" -IMAGE_TAG="${AZURE_ENV_IMAGE_TAG:-latest}" + ACR_NAME="${AZURE_CONTAINER_REGISTRY_NAME:-}" + ACR_ENDPOINT="${AZURE_CONTAINER_REGISTRY_ENDPOINT:-}" + RESOURCE_GROUP="${AZURE_RESOURCE_GROUP:-}" + BACKEND_CA="${BACKEND_CONTAINER_APP_NAME:-}" + MCP_CA="${MCP_CONTAINER_APP_NAME:-}" + FRONTEND_APP="${FRONTEND_WEB_APP_NAME:-}" + BACKEND_IMAGE="${BACKEND_IMAGE_NAME:-macaebackend}" + FRONTEND_IMAGE="${FRONTEND_IMAGE_NAME:-macaefrontend}" + MCP_IMAGE="${MCP_IMAGE_NAME:-macaemcp}" + FRONTEND_PORT="${FRONTEND_WEBSITES_PORT:-3000}" + BUILD_MODE="${AZURE_ENV_BUILD_MODE:-remote}" + IMAGE_TAG="${AZURE_ENV_IMAGE_TAG:-latest}" +fi require AZURE_CONTAINER_REGISTRY_NAME "${ACR_NAME}" require AZURE_CONTAINER_REGISTRY_ENDPOINT "${ACR_ENDPOINT}" @@ -100,7 +156,7 @@ for ctx in "${IMAGE_CTXS[@]}"; do done # --- WAF: temporarily relax ACR restrictions for build/push, restored on exit --- -DEPLOYMENT_TYPE="$(az group show --name "${RESOURCE_GROUP}" --query "tags.Type" -o tsv 2>/dev/null || true)" +DEPLOYMENT_TYPE="$(az group show --name "${RESOURCE_GROUP}" --query "tags.Type" -o tsv 2>/dev/null | tr -d '\r' || true)" restore_acr_waf() { if [ "${DEPLOYMENT_TYPE}" = "WAF" ]; then diff --git a/infra/scripts/post-provision/post_deploy.ps1 b/infra/scripts/post-provision/post_deploy.ps1 index b0e8e2f37..103982b44 100644 --- a/infra/scripts/post-provision/post_deploy.ps1 +++ b/infra/scripts/post-provision/post_deploy.ps1 @@ -322,6 +322,21 @@ function Get-ValuesUsingSolutionSuffix { # Endpoints (best-effort reconstruction; seed scripts will fail loudly if missing) $script:aiSearchEndpoint = "https://$($script:aiSearch).search.windows.net" + # AI Foundry account + project (naming convention: aif-, proj-) + $aiFoundryName = "aif-$solutionSuffix" + $foundryId = az cognitiveservices account show --name $aiFoundryName --resource-group $script:ResourceGroup --query "id" -o tsv 2>$null + if ($foundryId) { + $script:aiFoundryResourceId = $foundryId + if (-not $script:openaiEndpoint) { + $script:openaiEndpoint = az cognitiveservices account show --name $aiFoundryName --resource-group $script:ResourceGroup --query "properties.endpoint" -o tsv 2>$null + } + if (-not $script:projectEndpoint) { + # Project is a sub-resource (accounts/projects), construct endpoint from account's AI Foundry API base + $foundryApiBase = "https://$aiFoundryName.services.ai.azure.com" + $script:projectEndpoint = "$foundryApiBase/api/projects/proj-$solutionSuffix" + } + } + if (-not $script:storageAccount -or -not $script:aiSearch -or -not $script:backendUrl) { Write-Host "Error: Failed to reconstruct all required resource names." return $false @@ -589,6 +604,9 @@ try { Write-Host "Error: Both fallback methods failed." -ForegroundColor Red exit 1 } + } elseif (-not $script:projectEndpoint -or -not $script:aiFoundryResourceId) { + # Deployment outputs succeeded but missing some optional values — supplement via naming convention + Get-ValuesUsingSolutionSuffix | Out-Null } } diff --git a/infra/scripts/post-provision/post_deploy.sh b/infra/scripts/post-provision/post_deploy.sh index 1435a0873..4ffbf3394 100644 --- a/infra/scripts/post-provision/post_deploy.sh +++ b/infra/scripts/post-provision/post_deploy.sh @@ -368,6 +368,21 @@ get_values_using_solution_suffix() { backend_url="https://$backend_fqdn" ai_search_endpoint="https://$ai_search.search.windows.net" + # AI Foundry account + project (naming convention: aif-, proj-) + local ai_foundry_name="aif-$solution_suffix" + local foundry_id + foundry_id="$(az cognitiveservices account show --name "$ai_foundry_name" --resource-group "$resource_group" --query "id" -o tsv 2>/dev/null || true)" + if [ -n "$foundry_id" ]; then + ai_foundry_resource_id="$foundry_id" + if [ -z "$openai_endpoint" ]; then + openai_endpoint="$(az cognitiveservices account show --name "$ai_foundry_name" --resource-group "$resource_group" --query "properties.endpoint" -o tsv 2>/dev/null || true)" + fi + if [ -z "$project_endpoint" ]; then + # Project is a sub-resource (accounts/projects), construct endpoint from account's AI Foundry API base + project_endpoint="https://${ai_foundry_name}.services.ai.azure.com/api/projects/proj-${solution_suffix}" + fi + fi + if [ -z "$storage_account" ] || [ -z "$ai_search" ] || [ -z "$backend_url" ]; then error "Failed to reconstruct all required resource names." return 1 @@ -676,6 +691,9 @@ main() { if ! get_values_using_solution_suffix; then fatal "Both fallback methods failed." fi + elif [ -z "$project_endpoint" ] || [ -z "$ai_foundry_resource_id" ]; then + # Deployment outputs succeeded but missing optional values — supplement via naming convention + get_values_using_solution_suffix || true fi fi fi