@@ -357,6 +357,134 @@ load_configuration() {
357357 fi
358358}
359359
360+ # Verify that configured model deployments exist on the Azure OpenAI resource
361+ check_model_deployments () {
362+ echo " "
363+ echo -e " ${BLUE} 🤖 Verifying Model Deployments${NC} "
364+ echo " ================================="
365+
366+ local endpoint=" ${AZURE_OPENAI_ENDPOINT} "
367+ local api_key=" ${AZURE_OPENAI_API_KEY} "
368+ local has_api_key=false
369+ local token=" "
370+
371+ # Determine auth method
372+ if [[ -n " $api_key " ]] && [[ " $api_key " != * " your-" * ]] && [[ " $api_key " != * " placeholder" * ]] && [[ " $api_key " != * " key-placeholder" * ]]; then
373+ has_api_key=true
374+ fi
375+
376+ if [[ " $has_api_key " == false ]]; then
377+ if command -v az > /dev/null 2>&1 && az account show > /dev/null 2>&1 ; then
378+ token=$( az account get-access-token --resource " https://cognitiveservices.azure.com" --query " accessToken" -o tsv 2> /dev/null)
379+ if [[ -z " $token " ]]; then
380+ echo -e " ${YELLOW} ⚠️ Could not obtain Azure AD token, skipping deployment check${NC} "
381+ return 0
382+ fi
383+ else
384+ echo -e " ${YELLOW} ⚠️ No auth available, skipping deployment check${NC} "
385+ return 0
386+ fi
387+ fi
388+
389+ # Collect unique deployment names and their roles
390+ local code_deploy=" ${AISETTINGS__DEPLOYMENTNAME} "
391+ local chat_deploy=" ${AISETTINGS__CHATDEPLOYMENTNAME} "
392+
393+ # Build parallel arrays (bash 3 compatible, no associative arrays)
394+ local deploy_names=" "
395+ local deploy_roles=" "
396+
397+ if [[ -n " $code_deploy " ]]; then
398+ deploy_names=" $code_deploy "
399+ deploy_roles=" code model (migration agents)"
400+ fi
401+ if [[ -n " $chat_deploy " ]] && [[ " $chat_deploy " != " $code_deploy " ]]; then
402+ deploy_names=" ${deploy_names} |${chat_deploy} "
403+ deploy_roles=" ${deploy_roles} |chat model (portal & reports)"
404+ elif [[ -n " $chat_deploy " ]] && [[ -n " $deploy_roles " ]]; then
405+ deploy_roles=" ${deploy_roles} + chat model"
406+ fi
407+
408+ if [[ -z " $deploy_names " ]]; then
409+ echo -e " ${YELLOW} ⚠️ No deployment names configured, skipping check${NC} "
410+ return 0
411+ fi
412+
413+ local all_ok=true
414+ local api_version=" 2024-06-01"
415+ local idx=0
416+
417+ IFS=' |' read -ra _deploy_arr <<< " $deploy_names"
418+ IFS=' |' read -ra _role_arr <<< " $deploy_roles"
419+
420+ for deploy_name in " ${_deploy_arr[@]} " ; do
421+ local role=" ${_role_arr[$idx]} "
422+ idx=$(( idx + 1 ))
423+
424+ # Use a lightweight inference probe: POST a minimal (invalid) chat completion.
425+ # This only needs inference-level RBAC permissions.
426+ # Expected: 400 = deployment exists, 404 = not found, 200 = also exists.
427+ local test_url=" ${endpoint%/ } /openai/deployments/${deploy_name} /chat/completions?api-version=${api_version} "
428+ local tmp_resp
429+ tmp_resp=$( mktemp)
430+ local curl_args=(" -s" " -o" " $tmp_resp " " -w" " %{http_code}" " --connect-timeout" " 10" " --max-time" " 15" )
431+ local http_status=" "
432+ local post_body=' {"messages":[],"max_tokens":1}'
433+
434+ if [[ " $has_api_key " == true ]]; then
435+ http_status=$( curl " ${curl_args[@]} " -X POST -H " api-key: $api_key " -H " Content-Type: application/json" -d " $post_body " " $test_url " 2> /dev/null)
436+ else
437+ http_status=$( curl " ${curl_args[@]} " -X POST -H " Authorization: Bearer $token " -H " Content-Type: application/json" -d " $post_body " " $test_url " 2> /dev/null)
438+ fi
439+
440+ local body
441+ body=$( cat " $tmp_resp " 2> /dev/null)
442+ rm -f " $tmp_resp "
443+
444+ # 400 = deployment exists but our dummy request is invalid (expected)
445+ # 200 = deployment exists and responded
446+ # 404 = deployment truly not found
447+ if [[ " $http_status " == " 200" ]] || [[ " $http_status " == " 400" ]]; then
448+ echo -e " ${GREEN} ✅ Deployment '${deploy_name} ' exists${NC} (${role} )"
449+ elif [[ " $http_status " == " 404" ]]; then
450+ # Check error code to distinguish "deployment not found" from "endpoint not found"
451+ local error_code=" "
452+ if command -v jq > /dev/null 2>&1 ; then
453+ error_code=$( echo " $body " | jq -r ' (.error.code // empty)' 2> /dev/null)
454+ fi
455+ if [[ " $error_code " == " DeploymentNotFound" ]]; then
456+ echo -e " ${RED} ❌ Deployment '${deploy_name} ' NOT FOUND${NC} (${role} )"
457+ echo -e " ${YELLOW} Create this deployment in the Azure portal or update the name in Config/ai-config.local.env${NC} "
458+ all_ok=false
459+ else
460+ echo -e " ${RED} ❌ Deployment '${deploy_name} ' NOT FOUND (HTTP 404)${NC} (${role} )"
461+ echo -e " ${YELLOW} Create this deployment in the Azure portal or update the name in Config/ai-config.local.env${NC} "
462+ all_ok=false
463+ fi
464+ elif [[ " $http_status " == " 429" ]]; then
465+ echo -e " ${GREEN} ✅ Deployment '${deploy_name} ' exists${NC} (${role} ) ${YELLOW} (rate limited)${NC} "
466+ else
467+ local error_msg=" "
468+ if command -v jq > /dev/null 2>&1 ; then
469+ error_msg=$( echo " $body " | jq -r ' (.error.message // .error.code // empty)' 2> /dev/null)
470+ fi
471+ echo -e " ${YELLOW} ⚠️ Deployment '${deploy_name} ' check returned HTTP ${http_status}${NC} (${role} )"
472+ if [[ -n " $error_msg " ]]; then
473+ echo -e " ${YELLOW} Error: $error_msg ${NC} "
474+ fi
475+ fi
476+ done
477+
478+ echo " "
479+ if [[ " $all_ok " == false ]]; then
480+ echo -e " ${RED} ❌ One or more model deployments are missing.${NC} "
481+ echo -e " ${YELLOW} Fix: Verify deployment names in Config/ai-config.local.env match your Azure OpenAI resource.${NC} "
482+ return 1
483+ fi
484+
485+ return 0
486+ }
487+
360488# Pre-check: verify AI connectivity via API key or Azure AD (Entra ID) auth
361489check_ai_connectivity () {
362490 echo " "
@@ -495,6 +623,12 @@ check_ai_connectivity() {
495623 fi
496624
497625 echo " "
626+
627+ # Verify model deployments exist
628+ if ! check_model_deployments; then
629+ return 1
630+ fi
631+
498632 return 0
499633}
500634
@@ -1139,6 +1273,15 @@ run_test() {
11391273 echo -e " ${YELLOW} ⚠️ Smart chunking infrastructure not found${NC} "
11401274 fi
11411275
1276+ # Verify model deployments
1277+ echo " "
1278+ echo " Checking model deployments..."
1279+ if load_configuration > /dev/null 2>&1 && load_ai_config > /dev/null 2>&1 ; then
1280+ check_model_deployments
1281+ else
1282+ echo -e " ${YELLOW} ⚠️ Could not load config to verify deployments${NC} "
1283+ fi
1284+
11421285 echo " "
11431286 echo -e " ${GREEN} 🚀 Ready to run migration!${NC} "
11441287 echo " "
0 commit comments