diff --git a/scripts/validate_model_deployment_quota.ps1 b/scripts/validate_model_deployment_quota.ps1 index dda72971..000bc212 100644 --- a/scripts/validate_model_deployment_quota.ps1 +++ b/scripts/validate_model_deployment_quota.ps1 @@ -19,6 +19,18 @@ if ($MissingParams.Count -gt 0) { exit 1 } +# Check Azure login +try { + $accountCheck = az account show --output none 2>$null + if ($LASTEXITCODE -ne 0) { + Write-Error "❌ ERROR: You are not logged in to Azure CLI. Please run 'az login' to continue." + exit 1 + } +} catch { + Write-Error "❌ ERROR: Failed to verify Azure login. Please run 'az login' to continue." + exit 1 +} + # Load model deployments from parameter file $JsonContent = Get-Content -Path "./infra/main.parameters.json" -Raw | ConvertFrom-Json $aiModelDeployments = $JsonContent.parameters.$ModelsParameter.value diff --git a/scripts/validate_model_deployment_quota.sh b/scripts/validate_model_deployment_quota.sh old mode 100644 new mode 100755 index acf1e3b6..9b6b921d --- a/scripts/validate_model_deployment_quota.sh +++ b/scripts/validate_model_deployment_quota.sh @@ -40,6 +40,13 @@ if [[ ${#MISSING_PARAMS[@]} -ne 0 ]]; then exit 1 fi +# Check if user is logged in to Azure +if ! az account show > /dev/null 2>&1; then + echo "❌ ERROR: You are not logged in to Azure CLI." + echo "👉 Please run 'az login' to continue." + exit 1 +fi + # Load model definitions aiModelDeployments=$(jq -c ".parameters.$MODELS_PARAMETER.value[]" ./infra/main.parameters.json 2>/dev/null) if [[ $? -ne 0 || -z "$aiModelDeployments" ]]; then @@ -100,8 +107,7 @@ while IFS= read -r deployment; do type=${AZURE_ENV_MODEL_DEPLOYMENT_TYPE:-$(echo "$deployment" | jq -r '.sku.name')} capacity=${AZURE_ENV_MODEL_CAPACITY:-$(echo "$deployment" | jq -r '.sku.capacity')} - echo "" - echo "🔍 Validating model deployment: $name ..." + echo -e "🔍 Validation started for model deployment: \e[1m$name\e[0m in region \e[1m$LOCATION\e[0m with capacity \e[1m$capacity\e[0m tokens..." ./scripts/validate_model_quota.sh --location "$LOCATION" --model "$model" --capacity "$capacity" --deployment-type "$type" exit_code=$? @@ -109,13 +115,14 @@ while IFS= read -r deployment; do if [[ $exit_code -eq 2 ]]; then exit 1 fi - echo "❌ ERROR: Quota validation failed for model deployment: $name" + echo -e "\n❌ ERROR: Quota validation failed for model deployment: \033[1m$name\033[0m" quotaAvailable=false fi done <<< "$(echo "$aiModelDeployments")" if [[ "$quotaAvailable" = false ]]; then - echo "❌ ERROR: One or more model deployments failed quota validation." + echo -e "\n❌ ERROR: Quota validation failed — insufficient quota in all regions. Deployment cannot proceed." + echo -e "\nℹ️ Please request a quota increase at https://portal.azure.com/#blade/Microsoft_Azure_Capacity/UsageAndQuota and try again." exit 1 else echo "✅ All model deployments passed quota validation successfully." diff --git a/scripts/validate_model_quota.ps1 b/scripts/validate_model_quota.ps1 index e1516284..010fa3e1 100644 --- a/scripts/validate_model_quota.ps1 +++ b/scripts/validate_model_quota.ps1 @@ -14,34 +14,42 @@ $RecommendedRegions = @() $NotRecommendedRegions = @() $EligibleFallbacks = @() -# ------------------ Validate Inputs ------------------ -$MissingParams = @() -if (-not $Location) { $MissingParams += "location" } -if (-not $Model) { $MissingParams += "model" } -if (-not $Capacity -or $Capacity -le 0) { $MissingParams += "capacity" } - -if ($MissingParams.Count -gt 0) { - Write-Error "❌ ERROR: Missing or invalid parameters: $($MissingParams -join ', ')" - Write-Host "Usage: .\validate_model_quota.ps1 -Location -Model -Capacity [-DeploymentType ]" - exit 1 -} +function Validate-Inputs { + $MissingParams = @() + if (-not $Location) { $MissingParams += "location" } + if (-not $Model) { $MissingParams += "model" } + if (-not $Capacity -or $Capacity -le 0) { $MissingParams += "capacity" } + + if ($MissingParams.Count -gt 0) { + Write-Error "❌ ERROR: Missing or invalid parameters: $($MissingParams -join ', ')" + Write-Host "Usage: .\validate_model_quota.ps1 -Location -Model -Capacity [-DeploymentType ]" + exit 1 + } -if ($DeploymentType -ne "Standard" -and $DeploymentType -ne "GlobalStandard") { - Write-Error "❌ ERROR: Invalid deployment type: $DeploymentType. Allowed: 'Standard', 'GlobalStandard'" - exit 1 + if ($DeploymentType -ne "Standard" -and $DeploymentType -ne "GlobalStandard") { + Write-Error "❌ ERROR: Invalid deployment type: $DeploymentType. Allowed: 'Standard', 'GlobalStandard'" + exit 1 + } } -$ModelType = "OpenAI.$DeploymentType.$Model" +function Confirm-Action ($message) { + do { + $response = Read-Host "$message (y/n)" + if ($response -notmatch "^[YyNn]$") { + Write-Host "❌ Invalid input. Please enter 'y' or 'n'." + } + } while ($response -notmatch "^[YyNn]$") + return $response -match "^[Yy]$" +} function Check-Quota { param ([string]$Region) try { + $ModelType = "OpenAI.$DeploymentType.$Model" $ModelInfoRaw = az cognitiveservices usage list --location $Region --query "[?name.value=='$ModelType']" --output json 2>$null $ModelInfo = $ModelInfoRaw | ConvertFrom-Json - if (-not $ModelInfo -or $ModelInfo.Count -eq 0) { - return $null - } + if (-not $ModelInfo -or $ModelInfo.Count -eq 0) { return $null } $Current = [int]$ModelInfo[0].currentValue $Limit = [int]$ModelInfo[0].limit @@ -99,105 +107,102 @@ function Set-DeploymentValues($Region, $Capacity) { } } -# ------------------ Check Primary Region ------------------ -Write-Host "`n🔍 Checking quota in the requested region '$Location'..." -$PrimaryResult = Check-Quota -Region $Location +function Manual-Prompt { + while ($true) { + Write-Host "`n📍 Recommended regions (≥ $RECOMMENDED_TOKENS tokens available): $($RecommendedRegions -join ', ')" + $ManualRegion = Read-Host "Please enter a region you want to try manually" + if (-not $ManualRegion) { + Write-Host "❌ ERROR: No region entered. Exiting." + exit 1 + } -if ($PrimaryResult) { - $AllResults += $PrimaryResult - if ($PrimaryResult.Available -ge $Capacity) { - if ($RecommendedRegions -notcontains $Location -and $RecommendedRegions.Count -gt 0) { - Write-Host "`n⚠️ Selected region '$Location' has sufficient quota but is not among the recommended regions (≥ $RECOMMENDED_TOKENS tokens)." - Write-Host "🚨 Your application may not work as expected due to limited quota." - Write-Host "`nℹ️ Recommended regions: $($RecommendedRegions -join ', ')" - Write-Host "👉 It's advisable to deploy in one of these regions for optimal app performance." - $choice = Read-Host "❓ Do you want to choose a recommended region instead? (y/n)" - if ($choice -match "^[Yy]$") { - Show-Table - break - } else { - if ($Capacity -gt 200) { - Write-Host "`n⚠️ Reducing capacity to 200 in '$BicepParamsFile' for safer deployment..." - (Get-Content $BicepParamsFile) -replace "capacity\s*:\s*\d+", "capacity: 200" | Set-Content $BicepParamsFile - Write-Host "✅ Updated '$BicepParamsFile' with capacity 200." - } - Set-DeploymentValues $Location $Capacity - Write-Host "✅ Proceeding with '$Location' as selected." - exit 0 + $ManualCapacityStr = Read-Host "Enter the capacity you want to use (numeric value)" + if (-not ($ManualCapacityStr -as [int]) -or [int]$ManualCapacityStr -le 0) { + Write-Host "❌ Invalid capacity value. Try again." + continue + } + + $ManualCapacity = [int]$ManualCapacityStr + + if ($ManualCapacity -lt $RECOMMENDED_TOKENS) { + Write-Host "`n⚠️ You have entered a capacity of $ManualCapacity, which is less than the recommended minimum ($RECOMMENDED_TOKENS)." + Write-Host "🚨 This may cause performance issues or unexpected behavior." + Write-Host "ℹ️ Recommended regions (≥ $RECOMMENDED_TOKENS tokens available): $($RecommendedRegions -join ', ')" + if (-not (Confirm-Action "❓ Proceed anyway?")) { continue } + } + + Write-Host "`n🔍 Checking quota in region '$ManualRegion' for requested capacity: $ManualCapacity..." + $ManualResult = Check-Quota -Region $ManualRegion + + if (-not $ManualResult) { + Write-Host "⚠️ Could not retrieve quota info for region '$ManualRegion'. Try again." + continue + } + + if ($ManualResult.Available -ge $ManualCapacity) { + if ($ManualResult.Available -lt $RECOMMENDED_TOKENS) { + if (-not (Confirm-Action "❓ Proceed anyway?")) { continue } } - } else { - Write-Host "`n✅ Sufficient quota found in original region '$Location'." - Set-DeploymentValues $Location $Capacity + Set-DeploymentValues $ManualRegion $ManualCapacity + Write-Host "✅ Deployment values set. Exiting." exit 0 + } else { + Write-Host "❌ Quota in region '$ManualRegion' is insufficient. Available: $($ManualResult.Available), Required: $ManualCapacity" } - } else { - Write-Host "`n⚠️ Insufficient quota in '$Location'. Checking fallback regions..." } -} else { - Write-Host "`n⚠️ Could not retrieve quota info for region '$Location'." } -# ------------------ Check Fallback Regions ------------------ +# Start validation and quota checks +Validate-Inputs + +Write-Host "`n🔍 Checking quota in the requested region '$Location'..." +$PrimaryResult = Check-Quota -Region $Location +if ($PrimaryResult) { + $AllResults = @($AllResults) + $PrimaryResult +} + foreach ($region in $PreferredRegions) { - if ($region -eq $Location) { continue } - $result = Check-Quota -Region $region - if ($result) { - $AllResults += $result - if ($result.Available -ge $Capacity) { - $EligibleFallbacks += $region + if ($region -ne $Location) { + $fallbackResult = Check-Quota -Region $region + if ($fallbackResult) { + $AllResults = @($AllResults) + $fallbackResult + if ($fallbackResult.Available -ge $Capacity) { + $EligibleFallbacks += $region + } } } } Show-Table -if ($EligibleFallbacks.Count -gt 0) { - Write-Host "`n➡️ Found fallback regions with sufficient quota." +if ($Capacity -lt $RECOMMENDED_TOKENS) { + Write-Host "`n⚠️ You have entered a capacity of $Capacity, which is less than the recommended minimum ($RECOMMENDED_TOKENS)." + Write-Host "🚨 This may cause performance issues or unexpected behavior." + Write-Host "ℹ️ Recommended regions (≥ $RECOMMENDED_TOKENS tokens available):" if ($RecommendedRegions.Count -gt 0) { - Write-Host "`nℹ️ Recommended regions (≥ $RECOMMENDED_TOKENS tokens available):" foreach ($region in $RecommendedRegions) { Write-Host " - $region" } + } else { + Write-Host " ❌ No recommended regions currently available." } -} - -# ------------------ Manual Prompt if No Quota Found ------------------ -Write-Host "`n❌ ERROR: No region has sufficient quota." - -while ($true) { - $ManualRegion = Read-Host "`nPlease enter a region you want to try manually" - if (-not $ManualRegion) { - Write-Host "❌ ERROR: No region entered. Exiting." - exit 1 - } - - $ManualCapacityStr = Read-Host "Enter the capacity you want to use (numeric value)" - if (-not ($ManualCapacityStr -as [int]) -or [int]$ManualCapacityStr -le 0) { - Write-Host "❌ Invalid capacity value. Try again." - continue - } - - $ManualCapacity = [int]$ManualCapacityStr - $ManualResult = Check-Quota -Region $ManualRegion - - if (-not $ManualResult) { - Write-Host "⚠️ Could not retrieve quota info for region '$ManualRegion'. Try again." - continue + if (-not (Confirm-Action "❓ Proceed anyway?")) { + Manual-Prompt + exit 0 } +} - if ($ManualResult.Available -ge $ManualCapacity) { - if ($ManualResult.Available -lt $RECOMMENDED_TOKENS) { - Write-Host "`n⚠️ Region '$ManualRegion' has less than recommended ($RECOMMENDED_TOKENS) tokens." - $proceed = Read-Host "❓ Proceed anyway? (y/n)" - if ($proceed -notmatch "^[Yy]$") { - continue - } - } +if ($PrimaryResult -and $PrimaryResult.Available -ge $Capacity) { + Set-DeploymentValues $Location $Capacity + Write-Host "✅ Proceeding with '$Location' as selected." + exit 0 +} - Set-DeploymentValues $ManualRegion $ManualCapacity - Write-Host "✅ Deployment values set. Exiting." - exit 0 - } else { - Write-Host "❌ Quota in region '$ManualRegion' is insufficient. Available: $($ManualResult.Available), Required: $ManualCapacity" - } +Write-Host "`n❗ The originally selected region '$Location' does not have enough quota." +if ($EligibleFallbacks.Count -gt 0) { + Write-Host "👉 You can manually choose one of the recommended fallback regions for deployment." +} else { + Write-Host "❌ ERROR: No region has sufficient quota." } + +Manual-Prompt \ No newline at end of file diff --git a/scripts/validate_model_quota.sh b/scripts/validate_model_quota.sh old mode 100644 new mode 100755 index b1ca2bf8..3394e620 --- a/scripts/validate_model_quota.sh +++ b/scripts/validate_model_quota.sh @@ -4,44 +4,19 @@ LOCATION="" MODEL="" DEPLOYMENT_TYPE="Standard" CAPACITY=0 -RECOMMENDED_TOKENS=200 +RECOMMENDED_TOKENS=350 +TABLE_SHOWN=false +RECOMMENDATIONS_SHOWN=false +INITIAL_LOCATION="" ALL_REGIONS=('australiaeast' 'eastus' 'eastus2' 'francecentral' 'japaneast' 'norwayeast' 'southindia' 'swedencentral' 'uksouth' 'westus' 'westus3') -# Globals for recommended/not recommended regions RECOMMENDED_REGIONS=() NOT_RECOMMENDED_REGIONS=() ALL_RESULTS=() FALLBACK_RESULTS=() -# -------------------- Utility: Update .env and main.parameters.json -------------------- -update_env_and_parameters() { - local new_location="$1" - local new_capacity="$2" - - echo "➡️ Updating environment and parameters with Location='$new_location' and Capacity='$new_capacity'..." - - # Update the AZD environment - azd env set AZURE_AISERVICE_LOCATION "$new_location" - azd env set AZURE_ENV_MODEL_CAPACITY "$new_capacity" - - # Update main.parameters.json - local PARAM_FILE="./infra/main.parameters.json" - if [[ ! -f "$PARAM_FILE" ]]; then - echo "❌ ERROR: $PARAM_FILE not found, cannot update parameters." - return 1 - fi - - jq --arg loc "$new_location" \ - '.parameters.location.value = $loc' "$PARAM_FILE" > "${PARAM_FILE}.tmp" && mv "${PARAM_FILE}.tmp" "$PARAM_FILE" - - jq --argjson cap "$new_capacity" --arg model "$MODEL" \ - '(.parameters.aiModelDeployments.value[] | select(.name == $model) | .sku.capacity) |= $cap' "$PARAM_FILE" > "${PARAM_FILE}.tmp" && mv "${PARAM_FILE}.tmp" "$PARAM_FILE" - - echo "✅ Updated .env and $PARAM_FILE successfully." -} -# -------------------- Function: Check Quota -------------------- check_quota() { local region="$1" local MODEL_TYPE="OpenAI.$DEPLOYMENT_TYPE.$MODEL" @@ -50,7 +25,8 @@ check_quota() { output=$(az cognitiveservices usage list --location "$region" --query "[?name.value=='$MODEL_TYPE']" --output json 2>/dev/null) if [[ -z "$output" || "$output" == "[]" ]]; then - return 2 # No data + [[ "$region" == "$LOCATION" ]] && echo "⚠️ Could not retrieve the quota info for the region: $LOCATION" + return 2 fi local CURRENT_VALUE=$(echo "$output" | jq -r '.[0].currentValue // 0' | cut -d'.' -f1) @@ -59,188 +35,292 @@ check_quota() { ALL_RESULTS+=("$region|$LIMIT|$CURRENT_VALUE|$AVAILABLE") - if [[ "$AVAILABLE" -ge "$RECOMMENDED_TOKENS" ]]; then - RECOMMENDED_REGIONS+=("$region") - else - NOT_RECOMMENDED_REGIONS+=("$region") - fi + # if [[ "$region" == "$LOCATION" ]]; then + available=$AVAILABLE + # fi - if [[ "$AVAILABLE" -ge "$CAPACITY" ]]; then - return 0 + if (( AVAILABLE >= RECOMMENDED_TOKENS )); then + [[ ! " ${RECOMMENDED_REGIONS[*]} " =~ " $region " ]] && RECOMMENDED_REGIONS+=("$region") else - return 1 + [[ ! " ${NOT_RECOMMENDED_REGIONS[*]} " =~ " $region " ]] && NOT_RECOMMENDED_REGIONS+=("$region") fi + + (( AVAILABLE >= CAPACITY )) } -# -------------------- Input Validation -------------------- -while [[ $# -gt 0 ]]; do - case "$1" in - --model) - MODEL="$2"; shift 2 ;; - --capacity) - CAPACITY="$2"; shift 2 ;; - --deployment-type) - DEPLOYMENT_TYPE="$2"; shift 2 ;; - --location) - LOCATION="$2"; shift 2 ;; - *) - echo "❌ ERROR: Unknown option: $1"; exit 1 ;; - esac -done +print_recommended_warning() { + local location="$1" + local capacity="$2" + local matched_entry="" -[[ -z "$LOCATION" ]] && MISSING_PARAMS+=("location") -[[ -z "$MODEL" ]] && MISSING_PARAMS+=("model") -if ! [[ "$CAPACITY" =~ ^[0-9]+$ ]] || [[ "$CAPACITY" -le 0 ]]; then - MISSING_PARAMS+=("capacity") -fi + for entry in "${ALL_RESULTS[@]}"; do + IFS='|' read -r region _ _ _ <<< "$entry" + if [[ "$region" == "$location" ]]; then + matched_entry="$entry" + break + fi + done -if [[ ${#MISSING_PARAMS[@]} -ne 0 ]]; then - echo "❌ ERROR: Missing/invalid: ${MISSING_PARAMS[*]}" - echo "Usage: $0 --location --model --capacity [--deployment-type ]" - exit 1 -fi + if [[ -n "$matched_entry" ]]; then + IFS='|' read -r _ limit used available <<< "$matched_entry" + echo -e "\n📊 Available quota in \e[1m$location\e[0m: \e[1m$available\e[0m | Required for deployment: \e[1m$capacity\e[0m | Recommended for optimal performance: \e[1m$RECOMMENDED_TOKENS\e[0m" + if (( available < RECOMMENDED_TOKENS )); then + echo -e "\n⚠️ \033[1mWarning:\033[0m Region \e[1m$location\e[0m has available tokens less than the recommended threshold \e[1m$RECOMMENDED_TOKENS\e[0m." + echo "🚨 Your application may not work as expected due to limited quota." + echo -e "\nChecking other regions: \033[1m$(IFS=, ; echo "${ALL_REGIONS[*]}")\033[0m..." -if [[ "$DEPLOYMENT_TYPE" != "Standard" && "$DEPLOYMENT_TYPE" != "GlobalStandard" ]]; then - echo "❌ ERROR: Invalid deployment type: $DEPLOYMENT_TYPE" - exit 1 -fi + check_fallback_regions + else + echo -e "ℹ️ Sufficient quota available for deployment and optimal performance." + if (( capacity < RECOMMENDED_TOKENS )); then + echo -e "\n⚠️ Capacity is set to $capacity (default $CAPACITY), which may impact performance. This region has enough recommended tokens." + prompt_yes_no "❓ Do you want to update the token size or location to recommended? (y/n): " && { + ask_for_location + return 1 + } + fi + fi + else + echo -e "\n⚠️ Capacity entered is below recommended, but region quota data was not found." + fi -# -------------------- Main Logic Starts -------------------- -echo "🔍 Checking quota in '$LOCATION' for model '$MODEL'..." + if [[ ${#RECOMMENDED_REGIONS[@]} -gt 0 ]]; then + if [[ ${#RECOMMENDED_REGIONS[@]} -eq 1 && "${RECOMMENDED_REGIONS[0]}" == "$location" ]]; then + # Only one recommended region and it's the same as current location; skip showing + : + else + local recommended_list + recommended_list=$(IFS=, ; echo "${RECOMMENDED_REGIONS[*]}") + echo -e "ℹ️ Regions with sufficient tokens (\e[1m≥ $RECOMMENDED_TOKENS\e[0m ) for optimal performance: \033[1m$recommended_list\033[0m" + echo + fi + fi +} -check_quota "$LOCATION" -primary_status=$? +ask_for_location() { + echo -n "📍 Enter region: " + read -r new_location < /dev/tty -if [[ $primary_status -eq 1 ]]; then - primary_entry="${ALL_RESULTS[0]}" - IFS='|' read -r _ limit used available <<< "$primary_entry" - echo -e "\n⚠️ Insufficient quota in '$LOCATION' (Available: $available, Required: $CAPACITY). Checking fallback regions..." -fi + # Reject empty or numeric-only input + if [[ -z "$new_location" || "$new_location" =~ ^[0-9]+$ ]]; then + echo "❌ ERROR: Invalid region entered. Region cannot be empty or contain only numbers. Please enter again." + ask_for_location + return + fi -for region in "${ALL_REGIONS[@]}"; do - [[ "$region" == "$LOCATION" ]] && continue - check_quota "$region" - [[ $? -eq 0 ]] && FALLBACK_RESULTS+=("$region") -done + echo -n "🔢 Enter capacity (tokens): " + read -r new_capacity < /dev/tty -# -------------------- Quota Table Output -------------------- -echo "" -printf "%-5s | %-16s | %-33s | %-6s | %-6s | %-9s\n" "No." "Region" "Model Name" "Limit" "Used" "Available" -printf -- "---------------------------------------------------------------------------------------------\n" - -index=1 -REGIONS_WITH_QUOTA=() -for result in "${ALL_RESULTS[@]}"; do - IFS='|' read -r region limit used available <<< "$result" - if (( available >= 50 )); then - printf "| %-3s | %-16s | %-33s | %-6s | %-6s | %-9s |\n" "$index" "$region" "OpenAI.$DEPLOYMENT_TYPE.$MODEL" "$limit" "$used" "$available" - REGIONS_WITH_QUOTA+=("$region|$available") - ((index++)) + if ! [[ "$new_capacity" =~ ^[0-9]+$ ]] || (( new_capacity <= 0 )); then + echo "❌ Invalid capacity entered. Capacity cannot be characters. Please enter again." + ask_for_location + return fi -done -printf -- "---------------------------------------------------------------------------------------------\n" -# -------------------- Prompt if No Region Has Enough -------------------- -if [[ $primary_status -ne 0 && ${#FALLBACK_RESULTS[@]} -eq 0 ]]; then - echo -e "\n❌ No region has sufficient quota (≥ $CAPACITY tokens)." + local requested_location="$new_location" + local requested_capacity="$new_capacity" - max_available=0; max_region="" - for result in "${ALL_RESULTS[@]}"; do - IFS='|' read -r region limit used available <<< "$result" - if (( available > max_available )); then - max_available=$available - max_region=$region + # LOCATION="$new_location" + # CAPACITY="$new_capacity" + + echo -e "\n🔍 Checking quota in region '$requested_location' for requested capacity: $requested_capacity..." + + if check_quota "$requested_location"; then + if (( requested_capacity < RECOMMENDED_TOKENS )); then + print_recommended_warning "$requested_location" "$requested_capacity" || exit 0 + prompt_yes_no "❓ Proceed anyway with $requested_capacity tokens? (y/n): " || { + ask_for_location + } fi - done - if (( max_available == 0 )); then - echo "⚠️ No quota info from any region. Cannot proceed." - exit 1 + if (( available < requested_capacity )); then + echo -e "❌ Region '\033[1m$requested_location\033[0m' does not have sufficient quota for \033[1m$requested_capacity\033[0m tokens." + if prompt_yes_no "❓ Do you want to check for other regions with sufficient quota? (y/n): "; then + echo -e "ℹ️ Checking other regions for sufficient quota..." + check_fallback_regions + return + fi + else + LOCATION="$requested_location" + CAPACITY="$requested_capacity" + fi + + + + prompt_yes_no "❓ Do you want to proceed with deployment in '$LOCATION'? for AI Services (y/n): " || { + ask_for_location + return + } + + update_env_and_parameters "$LOCATION" "$CAPACITY" + echo -e "✅ Proceeding with deployment in \033[1m$LOCATION\033[0m for AI Services with capacity \033[1m$CAPACITY\033[0m tokens." + exit 0 + else + echo -e "\n❌ Quota insufficient in \033[1m$requested_location\033[0m (Available: \033[1m$available\033[0m, Required: \033[1m$requested_capacity\033[0m). \n Checking other regions: \033[1m$(IFS=, ; echo "${ALL_REGIONS[*]}")\033[0m..." + check_fallback_regions fi +} - echo "➡️ Highest available quota: $max_available tokens in '$max_region'." - echo -n "❓ Enter new capacity to use (<= $max_available): " - read -r new_capacity < /dev/tty +prompt_yes_no() { + local prompt="$1" + local response + echo -n "$prompt" + read -r response < /dev/tty + while [[ ! "$response" =~ ^[YyNn]$ ]]; do + echo "❌ Invalid input. Please enter 'y' or 'n': " + read -r response < /dev/tty + done + [[ "$response" =~ ^[Yy]$ ]] +} - if ! [[ "$new_capacity" =~ ^[0-9]+$ ]] || (( new_capacity > max_available )) || (( new_capacity <= 0 )); then - echo "❌ Invalid capacity entered. Exiting." - exit 1 - fi +update_env_and_parameters() { + local new_location="$1" + local new_capacity="$2" - echo -n "❓ Enter location to use (default: $max_region): " - read -r new_location < /dev/tty - new_location="${new_location:-$max_region}" + # Get current environment values + local current_location + local current_capacity - CAPACITY=$new_capacity - LOCATION=$new_location + current_location=$(azd env get-values --output json | jq -r '.AZURE_AISERVICE_LOCATION // empty') + current_capacity=$(azd env get-values --output json | jq -r '.AZURE_ENV_MODEL_CAPACITY // empty') - check_quota "$LOCATION" - [[ $? -eq 0 ]] || { echo "❌ Insufficient quota in '$LOCATION'. Exiting."; exit 1; } + # Check if update is needed + if [[ "$new_location" == "$current_location" && "$new_capacity" == "$current_capacity" ]]; then + echo "ℹ️ No changes detected in location or capacity. Skipping environment and parameter update." + return 0 + fi - update_env_and_parameters "$LOCATION" "$CAPACITY" - echo "✅ Deployment settings updated." - exit 0 -fi + echo "➡️ Updating environment and parameters with Location='$new_location' and Capacity='$new_capacity'..." -# -------------------- Handle Fallback Prompt -------------------- -ask_for_location() { - echo -e "\nPlease choose a region from the above list:" - echo -n "📍 Enter region: " - read -r new_location < /dev/tty + azd env set AZURE_AISERVICE_LOCATION "$new_location" + azd env set AZURE_ENV_MODEL_CAPACITY "$new_capacity" - if [[ -z "$new_location" ]]; then - echo "❌ ERROR: No location entered. Exiting." - exit 1 + local PARAM_FILE="./infra/main.parameters.json" + if [[ ! -f "$PARAM_FILE" ]]; then + echo "❌ ERROR: $PARAM_FILE not found, cannot update parameters." + return 1 fi - echo -n "🔢 Enter capacity (tokens): " - read -r new_capacity < /dev/tty + jq --arg loc "$new_location" \ + '.parameters.location.value = $loc' "$PARAM_FILE" > "${PARAM_FILE}.tmp" && mv "${PARAM_FILE}.tmp" "$PARAM_FILE" - if ! [[ "$new_capacity" =~ ^[0-9]+$ ]] || (( new_capacity <= 0 )); then - echo "❌ Invalid capacity entered." - ask_for_location - return + jq --argjson cap "$new_capacity" --arg model "$MODEL" \ + '(.parameters.aiModelDeployments.value[] | select(.name == $model) | .sku.capacity) |= $cap' "$PARAM_FILE" > "${PARAM_FILE}.tmp" && mv "${PARAM_FILE}.tmp" "$PARAM_FILE" +} + +show_table() { + local index=1 + local printed_any=0 + + for result in "${ALL_RESULTS[@]}"; do + IFS='|' read -r region limit used available <<< "$result" + if (( available >= CAPACITY )) && [[ -z "${printed_regions[$region]}" ]]; then + if (( printed_any == 0 )); then + echo -e "\n\e[1mBelow is the list of regions with their quota information which have minimum quota for the deployment:\e[0m" + echo -e "--------------------------------------------------------------------------------------------------" + echo -e "| No. | Region | Model Name | Limit | Used | Available |" + echo -e "--------------------------------------------------------------------------------------------------" + printed_any=1 + fi + printf "| %-3s | %-16s | %-33s | %-6s | %-6s | %-9s |\n" "$index" "$region" "OpenAI.$DEPLOYMENT_TYPE.$MODEL" "$limit" "$used" "$available" + ((index++)) + fi + done + if (( printed_any == 1 )); then + echo -e "--------------------------------------------------------------------------------------------------" fi +} + +check_fallback_regions() { + for region in "${ALL_REGIONS[@]}"; do + [[ "$region" == "$LOCATION" ]] && continue + check_quota "$region" && FALLBACK_RESULTS+=("$region") + done - CAPACITY=$new_capacity - LOCATION=$new_location + if [[ ${#FALLBACK_RESULTS[@]} -gt 0 ]]; then + echo -e "\n➡️ Found other regions with sufficient quota." + if [[ "$TABLE_SHOWN" == false ]]; then + show_table + TABLE_SHOWN=true + fi - check_quota "$LOCATION" - if [[ $? -eq 0 ]]; then - update_env_and_parameters "$LOCATION" "$CAPACITY" - echo "✅ Updated and ready to deploy in '$LOCATION'." - exit 0 + if [[ ${#RECOMMENDED_REGIONS[@]} -gt 0 ]]; then + echo -e "ℹ️ Regions with sufficient tokens (≥ $RECOMMENDED_TOKENS) for optimal performance: \033[1m$recommended_list\033[0m" + for region in "${RECOMMENDED_REGIONS[@]}"; do + echo " - $region" + done + echo + + if prompt_yes_no "❓ Do you want to proceed by selecting one of these regions? (y/n): "; then + ask_for_location + else + check_quota "$LOCATION" + if (( available < CAPACITY )); then + echo -e "⚠️ The selected region '\033[1m$LOCATION\033[0m' has only \033[1m$available\033[0m quota, but \033[1m$CAPACITY\033[0m is required." + echo -e "\033[1m⚠️ Proceeding may result in deployment failure due to insufficient quota.\033[0m" + + if ! prompt_yes_no "❓ Do you still want to proceed with deployment in '$LOCATION'? (y/n): "; then + echo "ℹ️ Please select another region with sufficient quota." + ask_for_location + else + print_recommended_warning "$LOCATION" "$available" || exit 0 + echo -e "✅ Proceeding with deployment in \033[1m$LOCATION\033[0m for AI Services with capacity \033[1m$CAPACITY\033[0m." + update_env_and_parameters "$LOCATION" "$CAPACITY" + exit 0 + fi + else + echo -e "✅ Proceeding with deployment in \033[1m$LOCATION\033[0m for AI Services with capacity \033[1m$CAPACITY\033[0m." + update_env_and_parameters "$LOCATION" "$CAPACITY" + exit 0 + fi + fi + fi else - echo "❌ Insufficient quota in '$LOCATION'. Try another." - ask_for_location + echo -e "\n❌ ERROR: No region has sufficient quota for the required deployment." + return 1 fi } -# -------------------- Final Decision Logic -------------------- -if [[ $primary_status -eq 0 ]]; then - - if [[ " ${NOT_RECOMMENDED_REGIONS[*]} " == *" $LOCATION "* ]]; then - recommended_list=$(IFS=, ; echo "${RECOMMENDED_REGIONS[*]}") - bold_regions=$(printf "\033[1m%s\033[0m" "$recommended_list") - echo -e "\n⚠️ \033[1mWarning:\033[0m Region '$LOCATION' has available tokens less than the recommended threshold ($RECOMMENDED_TOKENS)." - echo -e "🚨 Your application may not work as expected due to limited quota." - echo -e "\nℹ️ Recommended regions (≥ $RECOMMENDED_TOKENS tokens available): $bold_regions" - echo -e "👉 It's advisable to deploy in one of these regions for optimal app performance." - - echo -n "❓ Proceed anyway? (y/n): " - read -r proceed < /dev/tty - if [[ "$proceed" =~ ^[Yy]$ ]]; then - update_env_and_parameters "$LOCATION" "$CAPACITY" - echo "✅ Proceeding with '$LOCATION'." - exit 0 - else +# ---------- Parse Inputs ---------- +while [[ $# -gt 0 ]]; do + case "$1" in + --location) LOCATION="$2"; shift ;; + --model) MODEL="$2"; shift ;; + --deployment-type) DEPLOYMENT_TYPE="$2"; shift ;; + --capacity) CAPACITY="$2"; shift ;; + *) echo "❌ Unknown option: $1"; exit 1 ;; + esac + shift +done + +# ---------- Validate Inputs ---------- +if [[ -z "$LOCATION" || -z "$MODEL" || -z "$CAPACITY" || "$CAPACITY" -le 0 ]]; then + echo "❌ Missing required parameters. Usage: $0 --location --model --capacity " + exit 1 +fi + +# ---------- Start Process ---------- +INITIAL_LOCATION="$LOCATION" + +echo -e "🔍 Checking quota in the requested region \e[1m$LOCATION\e[0m with capacity \e[1m$CAPACITY\e[0m tokens..." + +if check_quota "$LOCATION"; then + if (( CAPACITY < RECOMMENDED_TOKENS )); then + print_recommended_warning "$LOCATION" "$CAPACITY" + prompt_yes_no "❓ Proceed anyway? (y/n): " || { ask_for_location - fi - else - update_env_and_parameters "$LOCATION" "$CAPACITY" - echo "✅ Quota is sufficient in '$LOCATION'. Proceeding." - exit 0 + exit 0 + } + else + echo -e "✅ Region \033[1m$LOCATION\033[0m has sufficient tokens \033[1m$CAPACITY\033[0m and meets the recommended threshold \033[1m$RECOMMENDED_TOKENS\033[0m tokens.\n🚀 Suitable for deployment and optimal application performance." fi + + update_env_and_parameters "$LOCATION" "$CAPACITY" + echo -e "✅ Proceeding with deployment in \033[1m$LOCATION\033[0m for AI Services with capacity \033[1m$CAPACITY\033[0m." + exit 0 else - ask_for_location -fi + primary_entry="${ALL_RESULTS[0]}" + IFS='|' read -r _ limit used available <<< "$primary_entry" + echo -e "\n❌ Quota insufficient in '\033[1m$LOCATION\033[0m' (Available: \033[1m$available\033[0m, Required: \033[1m$CAPACITY\033[0m). \n Checking other regions: \033[1m$(IFS=, ; echo "${ALL_REGIONS[*]}")\033[0m..." + check_fallback_regions +fi \ No newline at end of file