From f395a432f736e06e89abab43938fa6cd5f9f1a16 Mon Sep 17 00:00:00 2001 From: Priyanka-Microsoft Date: Thu, 12 Jun 2025 14:47:39 +0530 Subject: [PATCH 1/5] script updated --- azure.yaml | 2 +- scripts/validate_model_quota.ps1 | 78 ++++++++++++++++++++------------ scripts/validate_model_quota.sh | 63 +++++++++++++++----------- 3 files changed, 86 insertions(+), 57 deletions(-) diff --git a/azure.yaml b/azure.yaml index 1171536..129132f 100644 --- a/azure.yaml +++ b/azure.yaml @@ -35,5 +35,5 @@ hooks: run: > $location = if ($env:AZURE_AISERVICE_LOCATION) { $env:AZURE_AISERVICE_LOCATION } else { "japaneast" }; ./scripts/validate_model_deployment_quota.ps1 -SubscriptionId $env:AZURE_SUBSCRIPTION_ID -Location $location -ModelsParameter "aiModelDeployments" - interactive: false + interactive: true continueOnError: false \ No newline at end of file diff --git a/scripts/validate_model_quota.ps1 b/scripts/validate_model_quota.ps1 index 0328e1f..11b4d08 100644 --- a/scripts/validate_model_quota.ps1 +++ b/scripts/validate_model_quota.ps1 @@ -10,7 +10,6 @@ $MissingParams = @() if (-not $Location) { $MissingParams += "location" } if (-not $Model) { $MissingParams += "model" } if (-not $Capacity) { $MissingParams += "capacity" } -if (-not $DeploymentType) { $MissingParams += "deployment-type" } if ($MissingParams.Count -gt 0) { Write-Error "āŒ ERROR: Missing required parameters: $($MissingParams -join ', ')" @@ -35,7 +34,7 @@ function Check-Quota { try { $ModelInfoRaw = az cognitiveservices usage list --location $Region --query "[?name.value=='$ModelType']" --output json $ModelInfo = $ModelInfoRaw | ConvertFrom-Json - if (-not $ModelInfo) { return } + if (-not $ModelInfo) { return $null } $CurrentValue = ($ModelInfo | Where-Object { $_.name.value -eq $ModelType }).currentValue $Limit = ($ModelInfo | Where-Object { $_.name.value -eq $ModelType }).limit @@ -52,11 +51,23 @@ function Check-Quota { Available = $Available } } catch { - return + return $null } } -# First, check the user-specified region +function Show-Table { + Write-Host "`n-------------------------------------------------------------------------------------------------------------" + Write-Host "| No. | Region | Model Name | Limit | Used | Available |" + Write-Host "-------------------------------------------------------------------------------------------------------------" + $count = 1 + foreach ($entry in $AllResults) { + Write-Host ("| {0,-4} | {1,-16} | {2,-35} | {3,-7} | {4,-7} | {5,-9} |" -f $count, $entry.Region, $entry.Model, $entry.Limit, $entry.Used, $entry.Available) + $count++ + } + Write-Host "-------------------------------------------------------------------------------------------------------------" +} + +# ----------- First check the user-specified region ----------- Write-Host "`nšŸ” Checking quota in the requested region '$Location'..." $PrimaryResult = Check-Quota -Region $Location @@ -72,45 +83,52 @@ if ($PrimaryResult) { Write-Host "`nāš ļø Could not retrieve quota info for region '$Location'. Checking fallback regions..." } -# Remove primary region from fallback list +# ----------- Check all other fallback regions ----------- $FallbackRegions = $PreferredRegions | Where-Object { $_ -ne $Location } +$EligibleFallbacks = @() foreach ($region in $FallbackRegions) { $result = Check-Quota -Region $region if ($result) { $AllResults += $result + if ($result.Available -ge $Capacity) { + $EligibleFallbacks += $result + } } } -# Display Results Table -Write-Host "`n-------------------------------------------------------------------------------------------------------------" -Write-Host "| No. | Region | Model Name | Limit | Used | Available |" -Write-Host "-------------------------------------------------------------------------------------------------------------" - -$count = 1 -foreach ($entry in $AllResults) { - $modelShort = $entry.Model.Substring($entry.Model.LastIndexOf(".") + 1) - Write-Host ("| {0,-4} | {1,-16} | {2,-35} | {3,-7} | {4,-7} | {5,-9} |" -f $count, $entry.Region, $entry.Model, $entry.Limit, $entry.Used, $entry.Available) - $count++ -} -Write-Host "-------------------------------------------------------------------------------------------------------------" - -# Suggest fallback regions -$EligibleFallbacks = $AllResults | Where-Object { $_.Region -ne $Location -and $_.Available -ge $Capacity } +# ----------- Show Table of All Regions Checked ----------- +Show-Table +# ----------- If eligible fallback regions found, ask user ----------- if ($EligibleFallbacks.Count -gt 0) { Write-Host "`nāŒ Deployment cannot proceed in '$Location'." - Write-Host "āž”ļø You can retry using one of the following regions with sufficient quota:`n" - foreach ($region in $EligibleFallbacks) { - Write-Host " • $($region.Region) (Available: $($region.Available))" - } + Write-Host "āž”ļø Found fallback regions with sufficient quota." + + while ($true) { + Write-Host "`nPlease enter a fallback region from the list above to proceed:" + $NewLocation = Read-Host "Enter region" + + if (-not $NewLocation) { + Write-Host "āŒ No location entered. Exiting." + exit 1 + } + + $UserResult = Check-Quota -Region $NewLocation + if (-not $UserResult) { + Write-Host "āš ļø Could not retrieve quota info for region '$NewLocation'. Try again." + continue + } - Write-Host "`nšŸ”§ To proceed, run:" - Write-Host " azd env set AZURE_AISERVICE_LOCATION ''" - Write-Host "šŸ“Œ To confirm it's set correctly, run:" - Write-Host " azd env get-value AZURE_AISERVICE_LOCATION" - Write-Host "ā–¶ļø Once confirmed, re-run azd up to deploy the model in the new region." - exit 2 + if ($UserResult.Available -ge $Capacity) { + Write-Host "āœ… Sufficient quota found in '$NewLocation'. Proceeding with deployment." + azd env set AZURE_AISERVICE_LOCATION "$NewLocation" | Out-Null + Write-Host "āž”ļø Set AZURE_AISERVICE_LOCATION to '$NewLocation'." + exit 0 + } else { + Write-Host "āŒ Insufficient quota in '$NewLocation'. Try another." + } + } } Write-Error "`nāŒ ERROR: No available quota found in any region." diff --git a/scripts/validate_model_quota.sh b/scripts/validate_model_quota.sh index 2675257..57d2094 100644 --- a/scripts/validate_model_quota.sh +++ b/scripts/validate_model_quota.sh @@ -56,9 +56,7 @@ FALLBACK_RESULTS=() ROW_NO=1 # Print validating message only once -echo -e "\nšŸ” Validating model deployment: $MODEL ..." - -echo "šŸ” Checking quota in the requested region '$LOCATION'..." +echo "šŸ” Checking quota in the requested region '$LOCATION' for the Model '$MODEL'..." # -------------------- Function: Check Quota -------------------- check_quota() { @@ -129,27 +127,40 @@ if [[ $primary_status -eq 0 ]]; then exit 0 fi -if [[ ${#FALLBACK_RESULTS[@]} -gt 0 ]]; then - echo -e "\nāŒ Deployment cannot proceed in '$LOCATION'." - echo "āž”ļø You can retry using one of the following regions with sufficient quota:" - echo "" - for region in "${FALLBACK_RESULTS[@]}"; do - for result in "${ALL_RESULTS[@]}"; do - IFS='|' read -r rgn _ _ avail <<< "$result" - if [[ "$rgn" == "$region" ]]; then - echo " • $region (Available: $avail)" - break - fi - done - done - - echo -e "\nšŸ”§ To proceed, run:" - echo " azd env set AZURE_AISERVICE_LOCATION ''" - echo "šŸ“Œ To confirm it's set correctly, run:" - echo " azd env get-value AZURE_AISERVICE_LOCATION" - echo "ā–¶ļø Once confirmed, re-run azd up to deploy the model in the new region." - exit 2 -fi -echo -e "\nāŒ ERROR: No available quota found in any region." -exit 1 +# Function: Ask user for location and validate quota +ask_for_location() { + echo "Please enter any other location from the above table where you want to deploy AI Services:" + read LOCATION < /dev/tty + + # Validate user input + if [[ -z "$LOCATION" ]]; then + echo "āŒ ERROR: No location entered. Exiting." + exit 1 + fi + + echo "šŸ” Checking quota in '$LOCATION'..." + check_quota "$LOCATION" + user_region_status=$? + + if [[ $user_region_status -eq 0 ]]; then + echo "āœ… Sufficient quota found in '$LOCATION'. Proceeding with deployment." + azd env set AZURE_AISERVICE_LOCATION "$LOCATION" + echo "āž”ļø Set AZURE_AISERVICE_LOCATION to '$LOCATION'." + exit 0 + elif [[ $user_region_status -eq 2 ]]; then + echo "āš ļø Could not retrieve quota info for region: '$LOCATION'. Exiting." + exit 1 + else + echo "āŒ Insufficient quota in '$LOCATION'." + ask_for_location # **Recursively call the function until valid input is provided** + fi +} + +# Main Logic +if [[ ${#FALLBACK_RESULTS[@]} -gt 0 ]]; then + echo -e "\nāŒ Deployment cannot proceed in this location: '$LOCATION'." + echo "āž”ļø Found fallback regions with sufficient quota." + + ask_for_location # **Call function to prompt user for input** +fi \ No newline at end of file From 3e2e8d87fa7246c44b0e2ced8cd875681a8f01a4 Mon Sep 17 00:00:00 2001 From: Priyanka-Microsoft Date: Thu, 12 Jun 2025 15:11:18 +0530 Subject: [PATCH 2/5] regions only who has capacity above 50 --- scripts/validate_model_quota.ps1 | 11 ++++++----- scripts/validate_model_quota.sh | 10 ++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/scripts/validate_model_quota.ps1 b/scripts/validate_model_quota.ps1 index 11b4d08..46c13cc 100644 --- a/scripts/validate_model_quota.ps1 +++ b/scripts/validate_model_quota.ps1 @@ -56,15 +56,15 @@ function Check-Quota { } function Show-Table { - Write-Host "`n-------------------------------------------------------------------------------------------------------------" - Write-Host "| No. | Region | Model Name | Limit | Used | Available |" - Write-Host "-------------------------------------------------------------------------------------------------------------" + Write-Host "`n--------------------------------------------------------------------------------------------" + Write-Host "| No. | Region | Model Name | Limit | Used | Available |" + Write-Host "--------------------------------------------------------------------------------------------" $count = 1 foreach ($entry in $AllResults) { - Write-Host ("| {0,-4} | {1,-16} | {2,-35} | {3,-7} | {4,-7} | {5,-9} |" -f $count, $entry.Region, $entry.Model, $entry.Limit, $entry.Used, $entry.Available) + Write-Host ("| {0,-3} | {1,-14} | {2,-35} | {3,-5} | {4,-5} | {5,-9} |" -f $count, $entry.Region, $entry.Model, $entry.Limit, $entry.Used, $entry.Available) $count++ } - Write-Host "-------------------------------------------------------------------------------------------------------------" + Write-Host "--------------------------------------------------------------------------------------------" } # ----------- First check the user-specified region ----------- @@ -98,6 +98,7 @@ foreach ($region in $FallbackRegions) { } # ----------- Show Table of All Regions Checked ----------- +$AllResults = $AllResults | Where-Object { $_.Available -gt 50 } Show-Table # ----------- If eligible fallback regions found, ask user ----------- diff --git a/scripts/validate_model_quota.sh b/scripts/validate_model_quota.sh index 57d2094..958b482 100644 --- a/scripts/validate_model_quota.sh +++ b/scripts/validate_model_quota.sh @@ -110,14 +110,16 @@ done # -------------------- Print Results Table -------------------- echo "" -printf "%-6s | %-18s | %-35s | %-8s | %-8s | %-9s\n" "No." "Region" "Model Name" "Limit" "Used" "Available" -printf -- "-------------------------------------------------------------------------------------------------------------\n" +printf "%-5s | %-16s | %-33s | %-6s | %-6s | %-9s\n" "No." "Region" "Model Name" "Limit" "Used" "Available" +printf -- "---------------------------------------------------------------------------------------------\n" index=1 for result in "${ALL_RESULTS[@]}"; do IFS='|' read -r region limit used available <<< "$result" - printf "| %-4s | %-16s | %-33s | %-7s | %-7s | %-9s |\n" "$index" "$region" "$MODEL_TYPE" "$limit" "$used" "$available" - ((index++)) + if [[ "$available" -gt 50 ]]; then + printf "| %-3s | %-14s | %-31s | %-5s | %-5s | %-9s |\n" "$index" "$region" "$MODEL_TYPE" "$limit" "$used" "$available" + ((index++)) + fi done printf -- "-------------------------------------------------------------------------------------------------------------\n" From c17dfe88397aa2133abc61bf79e07d4cbfeb87e8 Mon Sep 17 00:00:00 2001 From: Priyanka-Microsoft Date: Thu, 12 Jun 2025 15:18:56 +0530 Subject: [PATCH 3/5] interactive true --- azure.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure.yaml b/azure.yaml index 129132f..5dc6faf 100644 --- a/azure.yaml +++ b/azure.yaml @@ -27,7 +27,7 @@ hooks: shell: sh run: > chmod u+r+x ./scripts/validate_model_deployment_quota.sh; chmod u+r+x ./scripts/validate_model_quota.sh; ./scripts/validate_model_deployment_quota.sh --SubscriptionId "$AZURE_SUBSCRIPTION_ID" --Location "${AZURE_AISERVICE_LOCATION:-japaneast}" --ModelsParameter "aiModelDeployments" - interactive: false + interactive: true continueOnError: false windows: From c7d9d4b6be16b13ea41995ffb199b6d64ac8582a Mon Sep 17 00:00:00 2001 From: Priyanka-Microsoft Date: Thu, 12 Jun 2025 15:22:01 +0530 Subject: [PATCH 4/5] header and data alignment --- scripts/validate_model_quota.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/validate_model_quota.sh b/scripts/validate_model_quota.sh index 958b482..9b8e243 100644 --- a/scripts/validate_model_quota.sh +++ b/scripts/validate_model_quota.sh @@ -117,7 +117,7 @@ index=1 for result in "${ALL_RESULTS[@]}"; do IFS='|' read -r region limit used available <<< "$result" if [[ "$available" -gt 50 ]]; then - printf "| %-3s | %-14s | %-31s | %-5s | %-5s | %-9s |\n" "$index" "$region" "$MODEL_TYPE" "$limit" "$used" "$available" + printf "| %-3s | %-16s | %-33s | %-6s | %-6s | %-9s |\n" "$index" "$region" "$MODEL_TYPE" "$limit" "$used" "$available" ((index++)) fi done From a68b091e7d59afa6712cc5cfafb540cf2f7f9827 Mon Sep 17 00:00:00 2001 From: Abdul-Microsoft Date: Thu, 12 Jun 2025 16:26:56 +0530 Subject: [PATCH 5/5] refactor: improve AI Foundry validation logic --- scripts/validate_model_deployment_quota.ps1 | 69 ++++++++++++--------- scripts/validate_model_deployment_quota.sh | 60 ++++++++++-------- 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/scripts/validate_model_deployment_quota.ps1 b/scripts/validate_model_deployment_quota.ps1 index 24df1d4..dda7297 100644 --- a/scripts/validate_model_deployment_quota.ps1 +++ b/scripts/validate_model_deployment_quota.ps1 @@ -15,58 +15,64 @@ if (-not $ModelsParameter) { $MissingParams += "ModelsParameter" } if ($MissingParams.Count -gt 0) { Write-Error "āŒ ERROR: Missing required parameters: $($MissingParams -join ', ')" + Write-Host "Usage: validate_model_deployment_quota.ps1 -SubscriptionId -Location -ModelsParameter " exit 1 } # Load model deployments from parameter file $JsonContent = Get-Content -Path "./infra/main.parameters.json" -Raw | ConvertFrom-Json -if (-not $JsonContent) { - Write-Error "āŒ ERROR: Failed to parse main.parameters.json. Ensure the JSON file is valid." - exit 1 -} - $aiModelDeployments = $JsonContent.parameters.$ModelsParameter.value if (-not $aiModelDeployments -or -not ($aiModelDeployments -is [System.Collections.IEnumerable])) { - Write-Error "āŒ ERROR: The specified property '$ModelsParameter' does not exist or is not an array." + Write-Error "āŒ ERROR: Failed to parse main.parameters.json or missing '$ModelsParameter'" exit 1 } -# Check if AI Foundry exists and has all required model deployments -$existing = $null +# Try to discover AI Foundry name if not set +if (-not $AiFoundryName -and $ResourceGroup) { + $AiFoundryName = az cognitiveservices account list ` + --resource-group $ResourceGroup ` + --query "sort_by([?kind=='AIServices'], &name)[0].name" ` + -o tsv 2>$null +} + +# Check if AI Foundry exists if ($AiFoundryName -and $ResourceGroup) { $existing = az cognitiveservices account show ` --name $AiFoundryName ` --resource-group $ResourceGroup ` --query "name" --output tsv 2>$null -} -if ($existing) { - $deployedModelsOutput = az cognitiveservices account deployment list ` - --name $AiFoundryName ` - --resource-group $ResourceGroup ` - --query "[].name" --output tsv 2>$null + if ($existing) { + # adding into .env + azd env set AZURE_AIFOUNDRY_NAME $existing | Out-Null - $deployedModels = @() - if ($deployedModelsOutput -is [string]) { - $deployedModels += $deployedModelsOutput - } elseif ($deployedModelsOutput) { - $deployedModels = $deployedModelsOutput -split "`r?`n" - } + $deployedModelsOutput = az cognitiveservices account deployment list ` + --name $AiFoundryName ` + --resource-group $ResourceGroup ` + --query "[].name" --output tsv 2>$null - $requiredDeployments = $aiModelDeployments | ForEach-Object { $_.name } - $missingDeployments = $requiredDeployments | Where-Object { $_ -notin $deployedModels } + $deployedModels = @() + if ($deployedModelsOutput -is [string]) { + $deployedModels += $deployedModelsOutput + } elseif ($deployedModelsOutput) { + $deployedModels = $deployedModelsOutput -split "`r?`n" + } + + $requiredDeployments = $aiModelDeployments | ForEach-Object { $_.name } + $missingDeployments = $requiredDeployments | Where-Object { $_ -notin $deployedModels } - if ($missingDeployments.Count -eq 0) { - Write-Host "ā„¹ļø AI Foundry '$AiFoundryName' exists and all required model deployments are already provisioned." - Write-Host "ā­ļø Skipping quota validation." - exit 0 - } else { - Write-Host "šŸ” AI Foundry exists, but the following model deployments are missing: $($missingDeployments -join ', ')" - Write-Host "āž”ļø Proceeding with quota validation for missing models..." + if ($missingDeployments.Count -eq 0) { + Write-Host "ā„¹ļø AI Foundry '$AiFoundryName' exists and all required model deployments are already provisioned." + Write-Host "ā­ļø Skipping quota validation." + exit 0 + } else { + Write-Host "šŸ” AI Foundry exists, but the following model deployments are missing: $($missingDeployments -join ', ')" + Write-Host "āž”ļø Proceeding with quota validation for missing models..." + } } } -# Run quota validation for all models +# Run quota validation az account set --subscription $SubscriptionId Write-Host "šŸŽÆ Active Subscription: $(az account show --query '[name, id]' --output tsv)" @@ -78,7 +84,8 @@ foreach ($deployment in $aiModelDeployments) { $type = if ($env:AZURE_ENV_MODEL_DEPLOYMENT_TYPE) { $env:AZURE_ENV_MODEL_DEPLOYMENT_TYPE } else { $deployment.sku.name } $capacity = if ($env:AZURE_ENV_MODEL_CAPACITY) { $env:AZURE_ENV_MODEL_CAPACITY } else { $deployment.sku.capacity } - Write-Host "`nšŸ” Validating model deployment: $name ..." + Write-Host "" + Write-Host "šŸ” Validating model deployment: $name ..." & .\scripts\validate_model_quota.ps1 -Location $Location -Model $model -Capacity $capacity -DeploymentType $type $exitCode = $LASTEXITCODE diff --git a/scripts/validate_model_deployment_quota.sh b/scripts/validate_model_deployment_quota.sh index a318803..acf1e3b 100644 --- a/scripts/validate_model_deployment_quota.sh +++ b/scripts/validate_model_deployment_quota.sh @@ -47,34 +47,44 @@ if [[ $? -ne 0 || -z "$aiModelDeployments" ]]; then exit 1 fi -# Check if AI Foundry exists and has all required model deployments -existing="" -if [[ -n "$AIFOUNDRY_NAME" && -n "$RESOURCE_GROUP" ]]; then - existing=$(az cognitiveservices account show --name "$AIFOUNDRY_NAME" --resource-group "$RESOURCE_GROUP" --query "name" --output tsv 2>/dev/null) +# Try to discover AI Foundry name if not set +if [[ -z "$AIFOUNDRY_NAME" && -n "$RESOURCE_GROUP" ]]; then + AIFOUNDRY_NAME=$(az cognitiveservices account list --resource-group "$RESOURCE_GROUP" \ + --query "sort_by([?kind=='AIServices'], &name)[0].name" -o tsv 2>/dev/null) fi -if [[ -n "$existing" ]]; then - existing_deployments=$(az cognitiveservices account deployment list \ - --name "$AIFOUNDRY_NAME" \ - --resource-group "$RESOURCE_GROUP" \ - --query "[].name" --output tsv 2>/dev/null) - - required_models=$(jq -r ".parameters.$MODELS_PARAMETER.value[].name" ./infra/main.parameters.json) - - missing_models=() - for model in $required_models; do - if ! grep -q -w "$model" <<< "$existing_deployments"; then - missing_models+=("$model") +# Check if AI Foundry exists +if [[ -n "$AIFOUNDRY_NAME" && -n "$RESOURCE_GROUP" ]]; then + existing=$(az cognitiveservices account show --name "$AIFOUNDRY_NAME" \ + --resource-group "$RESOURCE_GROUP" --query "name" --output tsv 2>/dev/null) + + if [[ -n "$existing" ]]; then + # adding into .env + azd env set AZURE_AIFOUNDRY_NAME "$existing" > /dev/null + + # Check model deployments + existing_deployments=$(az cognitiveservices account deployment list \ + --name "$AIFOUNDRY_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --query "[].name" --output tsv 2>/dev/null) + + required_models=$(jq -r ".parameters.$MODELS_PARAMETER.value[].name" ./infra/main.parameters.json) + + missing_models=() + for model in $required_models; do + if ! grep -q -w "$model" <<< "$existing_deployments"; then + missing_models+=("$model") + fi + done + + if [[ ${#missing_models[@]} -eq 0 ]]; then + echo "ā„¹ļø AI Foundry '$AIFOUNDRY_NAME' exists and all required model deployments are already provisioned." + echo "ā­ļø Skipping quota validation." + exit 0 + else + echo "šŸ” AI Foundry exists, but the following model deployments are missing: ${missing_models[*]}" + echo "āž”ļø Proceeding with quota validation for missing models..." fi - done - - if [[ ${#missing_models[@]} -eq 0 ]]; then - echo "ā„¹ļø AI Foundry '$AIFOUNDRY_NAME' exists and all required model deployments are already provisioned." - echo "ā­ļø Skipping quota validation." - exit 0 - else - echo "šŸ” AI Foundry exists, but the following model deployments are missing: ${missing_models[*]}" - echo "āž”ļø Proceeding with quota validation for missing models..." fi fi