Skip to content

Commit fc69c4f

Browse files
authored
Merge pull request #45 from microsoft/quota-check
Quota check
2 parents 18daca7 + 1df653a commit fc69c4f

4 files changed

Lines changed: 356 additions & 5 deletions

File tree

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ The diagram below illustrates the capabilities included in the template.
4949
6. If leveraging [One-click deployment](#quick-deploy).
5050
7. If leveraging [GitHub Actions](docs/github_actions_steps.md).
5151

52+
### Check Azure OpenAI Quota Availability
53+
54+
To ensure sufficient quota is available in your subscription, please follow **[quota check instructions guide](./docs/quota_check.md)** before deploying the solution.
55+
56+
### Services Enabled
57+
5258
For additional documentation of the default enabled services of this solution accelerator, please see:
5359

5460
1. [Azure Open AI Service](https://learn.microsoft.com/en-us/azure/ai-services/openai/)
@@ -89,7 +95,7 @@ Follow the post deployment steps [Post Deployment Steps](docs/github_code_spaces
8995

9096
### Region Availability
9197

92-
By default, this template uses AI models which may not be available in all Azure regions. Check for [up-to-date region availability](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#standard-deployment-model-availability) and select a region during deployment accordingly.
98+
By default, this template uses AI models which may not be available in all Azure regions. Please follow [quota check instructions guide](./docs/quota_check.md) before deploying the solution. Additionally, check for [up-to-date region availability](https://learn.microsoft.com/azure/ai-services/openai/concepts/models#standard-deployment-model-availability) and select a region during deployment accordingly.
9399

94100
### Costs
95101

@@ -99,16 +105,12 @@ You can estimate the cost of this project's architecture with [Azure's pricing c
99105

100106
This template has [Managed Identity](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview) built in to eliminate the need for developers to manage these credentials. Applications can use managed identities to obtain Microsoft Entra tokens without having to manage any credentials.
101107

102-
103108
## Resources
104109

105110
- [Azure AI Foundry documentation](https://learn.microsoft.com/en-us/azure/ai-studio/)
106111
- [Azure Well Architecture Framework documentation](https://learn.microsoft.com/en-us/azure/well-architected/)
107112
- [Azure OpenAI Service - Documentation, quickstarts, API reference - Azure AI services | Microsoft Learn](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/use-your-data)
108113
- [Azure AI Content Understanding documentation](https://learn.microsoft.com/en-us/azure/ai-services/content-understanding/)
109-
110-
111-
112114
---
113115

114116
## Disclaimers

docs/quota_check.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Check Quota Availability Before Deployment
2+
3+
Before deploying the accelerator, **ensure sufficient quota availability** for the required model.
4+
> **We recommend increasing the capacity to 100k tokens for optimal performance.**
5+
6+
## Login if you have not done so already
7+
```
8+
azd auth login
9+
```
10+
11+
## 📌 Default Models & Capacities:
12+
```
13+
gpt-4o:30, gpt-4o-mini:30, gpt-4:30, text-embedding-ada-002:80
14+
```
15+
## 📌 Default Regions:
16+
```
17+
eastus, uksouth, eastus2, northcentralus, swedencentral, westus, westus2, southcentralus, canadacentral
18+
```
19+
## Usage Scenarios:
20+
- No parameters passed → Default models and capacities will be checked in default regions.
21+
- Only model(s) provided → The script will check for those models in the default regions.
22+
- Only region(s) provided → The script will check default models in the specified regions.
23+
- Both models and regions provided → The script will check those models in the specified regions.
24+
- `--verbose` passed → Enables detailed logging output for debugging and traceability.
25+
26+
## **Input Formats**
27+
> Use the --models, --regions, and --verbose options for parameter handling:
28+
29+
✔️ Run without parameters to check default models & regions without verbose logging:
30+
```
31+
./quota_check.sh
32+
```
33+
✔️ Enable verbose logging:
34+
```
35+
./quota_check.sh --verbose
36+
```
37+
✔️ Check specific model(s) in default regions:
38+
```
39+
./quota_check.sh --models gpt-4o:30,text-embedding-ada-002:80
40+
```
41+
✔️ Check default models in specific region(s):
42+
```
43+
./quota_check.sh --regions eastus,westus
44+
```
45+
✔️ Passing Both models and regions:
46+
```
47+
./quota_check.sh --models gpt-4o:30 --regions eastus,westus2
48+
```
49+
✔️ All parameters combined:
50+
```
51+
./quota_check.sh --models gpt-4:30,text-embedding-ada-002:80 --regions eastus,westus --verbose
52+
```
53+
54+
## **Sample Output**
55+
The final table lists regions with available quota. You can select any of these regions for deployment.
56+
57+
![quota-check-output](../img/Documentation/quota-check-output.png)
58+
59+
---
60+
## **If using Azure Portal and Cloud Shell**
61+
62+
1. Navigate to the [Azure Portal](https://portal.azure.com).
63+
2. Click on **Azure Cloud Shell** in the top right navigation menu.
64+
3. Run the appropriate command based on your requirement:
65+
66+
**To check quota for the deployment**
67+
68+
```sh
69+
curl -L -o quota_check.sh "https://raw.githubusercontent.com/microsoft/Deploy-Your-AI-Application-In-Production/main/scripts/quota_check.sh"
70+
chmod +x quota_check.sh
71+
./quota_check.sh
72+
```
73+
- Refer to [Input Formats](#input-formats) for detailed commands.
74+
75+
## **If using VS Code or Codespaces**
76+
1. Open the terminal in VS Code or Codespaces.
77+
2. If you're using VS Code, click the dropdown on the right side of the terminal window, and select `Git Bash`.
78+
![git_bash](Images/git_bash.png)
79+
3. Navigate to the `scripts` folder where the script files are located and make the script as executable:
80+
```sh
81+
cd scripts
82+
chmod +x quota_check.sh
83+
```
84+
4. Run the appropriate script based on your requirement:
85+
86+
**To check quota for the deployment**
87+
88+
```sh
89+
./quota_check.sh
90+
```
91+
- Refer to [Input Formats](#input-formats) for detailed commands.
92+
93+
5. If you see the error `_bash: az: command not found_`, install Azure CLI:
94+
95+
```sh
96+
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
97+
az login
98+
```
99+
6. Rerun the script after installing Azure CLI.
12.6 KB
Loading

scripts/quota_check.sh

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#!/bin/bash
2+
# VERBOSE=false
3+
4+
MODELS=""
5+
REGIONS=""
6+
VERBOSE=false
7+
8+
while [[ $# -gt 0 ]]; do
9+
case "$1" in
10+
--models)
11+
MODELS="$2"
12+
shift 2
13+
;;
14+
--regions)
15+
REGIONS="$2"
16+
shift 2
17+
;;
18+
--verbose)
19+
VERBOSE=true
20+
shift
21+
;;
22+
*)
23+
echo "Unknown option: $1"
24+
exit 1
25+
;;
26+
esac
27+
done
28+
29+
# Fallback to defaults if not provided
30+
[[ -z "$MODELS" ]]
31+
[[ -z "$REGIONS" ]]
32+
33+
echo "Models: $MODELS"
34+
echo "Regions: $REGIONS"
35+
echo "Verbose: $VERBOSE"
36+
37+
for arg in "$@"; do
38+
if [ "$arg" = "--verbose" ]; then
39+
VERBOSE=true
40+
fi
41+
done
42+
43+
log_verbose() {
44+
if [ "$VERBOSE" = true ]; then
45+
echo "$1"
46+
fi
47+
}
48+
49+
# Default Models and Capacities (Comma-separated in "model:capacity" format)
50+
DEFAULT_MODEL_CAPACITY="gpt-4o:30,gpt-4o-mini:30,gpt-4:30,text-embedding-ada-002:80"
51+
52+
# Convert the comma-separated string into an array
53+
IFS=',' read -r -a MODEL_CAPACITY_PAIRS <<< "$DEFAULT_MODEL_CAPACITY"
54+
55+
echo "🔄 Fetching available Azure subscriptions..."
56+
SUBSCRIPTIONS=$(az account list --query "[?state=='Enabled'].{Name:name, ID:id}" --output tsv)
57+
SUB_COUNT=$(echo "$SUBSCRIPTIONS" | wc -l)
58+
59+
if [ "$SUB_COUNT" -eq 0 ]; then
60+
echo "❌ ERROR: No active Azure subscriptions found. Please log in using 'az login' and ensure you have an active subscription."
61+
exit 1
62+
elif [ "$SUB_COUNT" -eq 1 ]; then
63+
# If only one subscription, automatically select it
64+
AZURE_SUBSCRIPTION_ID=$(echo "$SUBSCRIPTIONS" | awk '{print $2}')
65+
if [ -z "$AZURE_SUBSCRIPTION_ID" ]; then
66+
echo "❌ ERROR: No active Azure subscriptions found. Please log in using 'az login' and ensure you have an active subscription."
67+
exit 1
68+
fi
69+
echo "✅ Using the only available subscription: $AZURE_SUBSCRIPTION_ID"
70+
else
71+
# If multiple subscriptions exist, prompt the user to choose one
72+
echo "Multiple subscriptions found:"
73+
echo "$SUBSCRIPTIONS" | awk '{print NR")", $1, "-", $2}'
74+
75+
while true; do
76+
echo "Enter the number of the subscription to use:"
77+
read SUB_INDEX
78+
79+
# Validate user input
80+
if [[ "$SUB_INDEX" =~ ^[0-9]+$ ]] && [ "$SUB_INDEX" -ge 1 ] && [ "$SUB_INDEX" -le "$SUB_COUNT" ]; then
81+
AZURE_SUBSCRIPTION_ID=$(echo "$SUBSCRIPTIONS" | awk -v idx="$SUB_INDEX" 'NR==idx {print $2}')
82+
echo "✅ Selected Subscription: $AZURE_SUBSCRIPTION_ID"
83+
break
84+
else
85+
echo "❌ Invalid selection. Please enter a valid number from the list."
86+
fi
87+
done
88+
fi
89+
90+
91+
# Set the selected subscription
92+
az account set --subscription "$AZURE_SUBSCRIPTION_ID"
93+
echo "🎯 Active Subscription: $(az account show --query '[name, id]' --output tsv)"
94+
95+
# Default Regions to check (Comma-separated, now configurable)
96+
DEFAULT_REGIONS="eastus,uksouth,eastus2,northcentralus,swedencentral,westus,westus2,southcentralus,canadacentral"
97+
IFS=',' read -r -a DEFAULT_REGION_ARRAY <<< "$DEFAULT_REGIONS"
98+
99+
# Read parameters (if any)
100+
IFS=',' read -r -a USER_PROVIDED_PAIRS <<< "$MODELS"
101+
USER_REGION="$REGIONS"
102+
103+
IS_USER_PROVIDED_PAIRS=false
104+
105+
if [ ${#USER_PROVIDED_PAIRS[@]} -lt 1 ]; then
106+
echo "No parameters provided, using default model-capacity pairs: ${MODEL_CAPACITY_PAIRS[*]}"
107+
else
108+
echo "Using provided model and capacity pairs: ${USER_PROVIDED_PAIRS[*]}"
109+
IS_USER_PROVIDED_PAIRS=true
110+
MODEL_CAPACITY_PAIRS=("${USER_PROVIDED_PAIRS[@]}")
111+
fi
112+
113+
declare -a FINAL_MODEL_NAMES
114+
declare -a FINAL_CAPACITIES
115+
declare -a TABLE_ROWS
116+
117+
for PAIR in "${MODEL_CAPACITY_PAIRS[@]}"; do
118+
MODEL_NAME=$(echo "$PAIR" | cut -d':' -f1 | tr '[:upper:]' '[:lower:]')
119+
CAPACITY=$(echo "$PAIR" | cut -d':' -f2)
120+
121+
if [ -z "$MODEL_NAME" ] || [ -z "$CAPACITY" ]; then
122+
echo "❌ ERROR: Invalid model and capacity pair '$PAIR'. Both model and capacity must be specified."
123+
exit 1
124+
fi
125+
126+
FINAL_MODEL_NAMES+=("$MODEL_NAME")
127+
FINAL_CAPACITIES+=("$CAPACITY")
128+
129+
done
130+
131+
echo "🔄 Using Models: ${FINAL_MODEL_NAMES[*]} with respective Capacities: ${FINAL_CAPACITIES[*]}"
132+
echo "----------------------------------------"
133+
134+
# Check if the user provided a region, if not, use the default regions
135+
if [ -n "$USER_REGION" ]; then
136+
echo "🔍 User provided region: $USER_REGION"
137+
IFS=',' read -r -a REGIONS <<< "$USER_REGION"
138+
else
139+
echo "No region specified, using default regions: ${DEFAULT_REGION_ARRAY[*]}"
140+
REGIONS=("${DEFAULT_REGION_ARRAY[@]}")
141+
APPLY_OR_CONDITION=true
142+
fi
143+
144+
echo "✅ Retrieved Azure regions. Checking availability..."
145+
INDEX=1
146+
147+
VALID_REGIONS=()
148+
for REGION in "${REGIONS[@]}"; do
149+
log_verbose "----------------------------------------"
150+
log_verbose "🔍 Checking region: $REGION"
151+
152+
QUOTA_INFO=$(az cognitiveservices usage list --location "$REGION" --output json | tr '[:upper:]' '[:lower:]')
153+
if [ -z "$QUOTA_INFO" ]; then
154+
log_verbose "⚠️ WARNING: Failed to retrieve quota for region $REGION. Skipping."
155+
continue
156+
fi
157+
158+
TEXT_EMBEDDING_AVAILABLE=false
159+
AT_LEAST_ONE_MODEL_AVAILABLE=false
160+
TEMP_TABLE_ROWS=()
161+
162+
for index in "${!FINAL_MODEL_NAMES[@]}"; do
163+
MODEL_NAME="${FINAL_MODEL_NAMES[$index]}"
164+
REQUIRED_CAPACITY="${FINAL_CAPACITIES[$index]}"
165+
FOUND=false
166+
INSUFFICIENT_QUOTA=false
167+
168+
if [ "$MODEL_NAME" = "text-embedding-ada-002" ]; then
169+
MODEL_TYPES=("openai.standard.$MODEL_NAME")
170+
else
171+
MODEL_TYPES=("openai.standard.$MODEL_NAME" "openai.globalstandard.$MODEL_NAME")
172+
fi
173+
174+
for MODEL_TYPE in "${MODEL_TYPES[@]}"; do
175+
FOUND=false
176+
INSUFFICIENT_QUOTA=false
177+
log_verbose "🔍 Checking model: $MODEL_NAME with required capacity: $REQUIRED_CAPACITY ($MODEL_TYPE)"
178+
179+
MODEL_INFO=$(echo "$QUOTA_INFO" | awk -v model="\"value\": \"$MODEL_TYPE\"" '
180+
BEGIN { RS="},"; FS="," }
181+
$0 ~ model { print $0 }
182+
')
183+
184+
if [ -z "$MODEL_INFO" ]; then
185+
FOUND=false
186+
log_verbose "⚠️ WARNING: No quota information found for model: $MODEL_NAME in region: $REGION for model type: $MODEL_TYPE."
187+
continue
188+
fi
189+
190+
if [ -n "$MODEL_INFO" ]; then
191+
FOUND=true
192+
CURRENT_VALUE=$(echo "$MODEL_INFO" | awk -F': ' '/"currentvalue"/ {print $2}' | tr -d ',' | tr -d ' ')
193+
LIMIT=$(echo "$MODEL_INFO" | awk -F': ' '/"limit"/ {print $2}' | tr -d ',' | tr -d ' ')
194+
195+
CURRENT_VALUE=${CURRENT_VALUE:-0}
196+
LIMIT=${LIMIT:-0}
197+
198+
CURRENT_VALUE=$(echo "$CURRENT_VALUE" | cut -d'.' -f1)
199+
LIMIT=$(echo "$LIMIT" | cut -d'.' -f1)
200+
201+
AVAILABLE=$((LIMIT - CURRENT_VALUE))
202+
log_verbose "✅ Model: $MODEL_TYPE | Used: $CURRENT_VALUE | Limit: $LIMIT | Available: $AVAILABLE"
203+
204+
if [ "$AVAILABLE" -ge "$REQUIRED_CAPACITY" ]; then
205+
FOUND=true
206+
if [ "$MODEL_NAME" = "text-embedding-ada-002" ]; then
207+
TEXT_EMBEDDING_AVAILABLE=true
208+
fi
209+
AT_LEAST_ONE_MODEL_AVAILABLE=true
210+
TEMP_TABLE_ROWS+=("$(printf "| %-4s | %-20s | %-43s | %-10s | %-10s | %-10s |" "$INDEX" "$REGION" "$MODEL_TYPE" "$LIMIT" "$CURRENT_VALUE" "$AVAILABLE")")
211+
else
212+
INSUFFICIENT_QUOTA=true
213+
fi
214+
fi
215+
216+
if [ "$FOUND" = false ]; then
217+
log_verbose "❌ No models found for model: $MODEL_NAME in region: $REGION (${MODEL_TYPES[*]})"
218+
219+
elif [ "$INSUFFICIENT_QUOTA" = true ]; then
220+
log_verbose "⚠️ Model $MODEL_NAME in region: $REGION has insufficient quota (${MODEL_TYPES[*]})."
221+
fi
222+
done
223+
done
224+
225+
if { [ "$IS_USER_PROVIDED_PAIRS" = true ] && [ "$INSUFFICIENT_QUOTA" = false ] && [ "$FOUND" = true ]; } || { [ "$TEXT_EMBEDDING_AVAILABLE" = true ] && { [ "$APPLY_OR_CONDITION" != true ] || [ "$AT_LEAST_ONE_MODEL_AVAILABLE" = true ]; }; }; then
226+
VALID_REGIONS+=("$REGION")
227+
TABLE_ROWS+=("${TEMP_TABLE_ROWS[@]}")
228+
INDEX=$((INDEX + 1))
229+
elif [ ${#USER_PROVIDED_PAIRS[@]} -eq 0 ]; then
230+
echo "🚫 Skipping $REGION as it does not meet quota requirements."
231+
fi
232+
233+
done
234+
235+
if [ ${#TABLE_ROWS[@]} -eq 0 ]; then
236+
echo "--------------------------------------------------------------------------------------------------------------------"
237+
238+
echo "❌ No regions have sufficient quota for all required models. Please request a quota increase: https://aka.ms/oai/stuquotarequest"
239+
else
240+
echo "---------------------------------------------------------------------------------------------------------------------"
241+
printf "| %-4s | %-20s | %-43s | %-10s | %-10s | %-10s |\n" "No." "Region" "Model Name" "Limit" "Used" "Available"
242+
echo "---------------------------------------------------------------------------------------------------------------------"
243+
for ROW in "${TABLE_ROWS[@]}"; do
244+
echo "$ROW"
245+
done
246+
echo "---------------------------------------------------------------------------------------------------------------------"
247+
echo "➡️ To request a quota increase, visit: https://aka.ms/oai/stuquotarequest"
248+
fi
249+
250+
echo "✅ Script completed."

0 commit comments

Comments
 (0)