Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 84 additions & 18 deletions infra/scripts/post-provision/Build-And-Push-Images.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,

Expand Down Expand Up @@ -142,25 +153,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

Comment thread
NirajC3-Microsoft marked this conversation as resolved.
# 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 @(
Expand Down
113 changes: 82 additions & 31 deletions infra/scripts/post-provision/build_and_push_images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -87,40 +94,84 @@ if [ "${AZURE_ENV_SKIP_IMAGE_BUILD:-}" = "true" ]; then
exit 0
fi

if ! command -v jq >/dev/null 2>&1; then
echo "ERROR: 'jq' is required to update Container App images and ingress ports." >&2
exit 1
fi
# --- Determine configuration source -----------------------------------------
ARG_RESOURCE_GROUP="${1:-}"

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}"
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}"
Comment thread
NirajC3-Microsoft marked this conversation as resolved.

# 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:-<not found>} (${ACR_ENDPOINT:-<not found>})"
echo " Backend CA: ${BACKEND_CA:-<not found>}"
echo " MCP CA: ${MCP_CA:-<not found>}"
echo " Frontend App: ${FRONTEND_APP:-<not found>}"
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}"
Expand Down Expand Up @@ -155,7 +206,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
Expand Down
18 changes: 18 additions & 0 deletions infra/scripts/post-provision/post_deploy.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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-<suffix>, proj-<suffix>)
$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
}
Comment thread
NirajC3-Microsoft marked this conversation as resolved.
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
Expand Down Expand Up @@ -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
}
}

Expand Down
18 changes: 18 additions & 0 deletions infra/scripts/post-provision/post_deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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-<suffix>, proj-<suffix>)
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
Comment thread
NirajC3-Microsoft marked this conversation as resolved.

if [ -z "$storage_account" ] || [ -z "$ai_search" ] || [ -z "$backend_url" ]; then
error "Failed to reconstruct all required resource names."
return 1
Expand Down Expand Up @@ -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
Expand Down