mirror of
https://github.com/Azure-Samples/graphrag-accelerator.git
synced 2025-06-27 04:39:57 +00:00
269 lines
11 KiB
Bash
Executable File
269 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -eu # use set -eux for debugging
|
|
|
|
function load_env_variables() {
|
|
set -a
|
|
source .env
|
|
set +a
|
|
}
|
|
|
|
function checkRequiredParams () {
|
|
requiredParams=(
|
|
LOCATION
|
|
RESOURCE_GROUP
|
|
SUBSCRIPTION_ID
|
|
AAD_CLIENT_ID
|
|
AAD_OBJECT_ID
|
|
AAD_TENANT_ID
|
|
)
|
|
local paramsFile=$1
|
|
for param in "${requiredParams[@]}"; do
|
|
local paramValue=$(jq -r .$param < $paramsFile)
|
|
if [ "null" == "$paramValue" ] || [ -z "$paramValue" ]; then
|
|
echo "Parameter $param is required, exiting..."
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function populateRequiredParams () {
|
|
local paramsFile=$1
|
|
printf "Checking required parameters... "
|
|
checkRequiredParams $paramsFile
|
|
# The jq command below sets environment variables based on the key-value pairs in a JSON-formatted file
|
|
eval $(jq -r 'to_entries | .[] | "export \(.key)=\(.value)"' $paramsFile)
|
|
printf "Done.\n"
|
|
}
|
|
|
|
function set_variables() {
|
|
printf "Setting environment variables...\n"
|
|
SUBSCRIPTION_ID=${SUBSCRIPTION_ID:-""}
|
|
RESOURCE_GROUP=${RESOURCE_GROUP:-""}
|
|
LOCATION=${LOCATION:-""}
|
|
AAD_CLIENT_ID=${AAD_CLIENT_ID:-""}
|
|
AAD_OBJECT_ID=${AAD_OBJECT_ID:-""}
|
|
AAD_TENANT_ID=${AAD_TENANT_ID:-""}
|
|
AAD_TOKEN_ISSUER_URL=${AAD_TOKEN_ISSUER_URL:-"https://login.microsoftonline.com/$AAD_TENANT_ID/v2.0"}
|
|
IMAGE_NAME=${IMAGE_NAME:-"graphrag:frontend"}
|
|
REGISTRY_NAME=${REGISTRY_NAME:-"${RESOURCE_GROUP}reg"}
|
|
APP_SERVICE_PLAN=${APP_SERVICE_PLAN:-"${RESOURCE_GROUP}-asp"}
|
|
WEB_APP=${WEB_APP:-"${RESOURCE_GROUP}-playground"}
|
|
WEB_APP_IDENTITY=${WEB_APP_IDENTITY:-"${WEB_APP}-identity"}
|
|
#BACKEND_RESOURCE_GROUP=${BACKEND_RESOURCE_GROUP:-""} # needed for backend outbound vnet integration
|
|
printf "Done setting environment variables.\n"
|
|
}
|
|
|
|
function create_resource_group {
|
|
printf "Setting subsctiption to $SUBSCRIPTION_ID and Creating resource group...\n"
|
|
az account set --subscription $SUBSCRIPTION_ID > /dev/null
|
|
az group create --name $RESOURCE_GROUP --location $LOCATION > /dev/null
|
|
printf "Resource group created.\n"
|
|
}
|
|
|
|
function create_acr() {
|
|
printf "Creating Azure Container Registry...\n"
|
|
az acr create --resource-group $RESOURCE_GROUP \
|
|
--name $REGISTRY_NAME \
|
|
--sku Basic \
|
|
--admin-enabled false > /dev/null
|
|
printf "Azure Container Registry created.\n"
|
|
}
|
|
|
|
function build_and_push_image() {
|
|
printf "Building and pushing image...\n"
|
|
local SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]:-$0}"; )" &> /dev/null && pwd 2> /dev/null; )";
|
|
az acr build --registry $REGISTRY_NAME -f $SCRIPT_DIR/../docker/Dockerfile-frontend --image $IMAGE_NAME $SCRIPT_DIR/../
|
|
printf "Image built and pushed.\n"
|
|
}
|
|
|
|
function create_app_service_plan() {
|
|
printf "Creating app service plan...\n"
|
|
az appservice plan create --name $APP_SERVICE_PLAN \
|
|
--resource-group $RESOURCE_GROUP \
|
|
--sku B3 \
|
|
--is-linux > /dev/null
|
|
printf "App service plan created.\n"
|
|
}
|
|
|
|
|
|
function create_web_app_identity() {
|
|
printf "Creating web app identity...\n"
|
|
IDENTITY_RESULT=$(az identity create --resource-group $RESOURCE_GROUP --name $WEB_APP_IDENTITY --output json)
|
|
WEBAPP_IDENTITY_ID=$(jq -r .id <<< $IDENTITY_RESULT)
|
|
WEBAPP_IDENTITY_OBJECT_ID=$(jq -r .principalId <<< $IDENTITY_RESULT)
|
|
WEBAPP_IDENTITY_CLIENT_ID=$(jq -r .clientId <<< $IDENTITY_RESULT)
|
|
printf "Web app identity created.\n"
|
|
}
|
|
|
|
function configure_registry_credentials() {
|
|
printf "Configuring registry credentials...\n"
|
|
ACR_ID=$(az acr show --name $REGISTRY_NAME --resource-group $RESOURCE_GROUP --query id --output tsv)
|
|
az role assignment create --assignee $WEBAPP_IDENTITY_CLIENT_ID \
|
|
--role AcrPull \
|
|
--scope $ACR_ID > /dev/null
|
|
printf "Registry credentials configured.\n"
|
|
}
|
|
|
|
function create_web_app() {
|
|
printf "Creating web app...\n"
|
|
az webapp create --resource-group $RESOURCE_GROUP \
|
|
--plan $APP_SERVICE_PLAN \
|
|
--name $WEB_APP \
|
|
--assign-identity $WEBAPP_IDENTITY_ID \
|
|
--acr-use-identity \
|
|
--acr-identity $WEBAPP_IDENTITY_ID \
|
|
--https-only true \
|
|
--container-image-name $REGISTRY_NAME.azurecr.io/$IMAGE_NAME > /dev/null
|
|
printf "Web app created.\n"
|
|
}
|
|
|
|
function configure_app_settings() {
|
|
printf "Configuring app settings...\n"
|
|
APP_SETTINGS=""
|
|
while IFS='=' read -r name value
|
|
do
|
|
value="${value%\"}" # Remove opening quote
|
|
value="${value#\"}" # Remove closing quote
|
|
APP_SETTINGS="$APP_SETTINGS $name=$value"
|
|
done < .env
|
|
# echo $APP_SETTINGS
|
|
az webapp config appsettings set --name $WEB_APP \
|
|
--resource-group $RESOURCE_GROUP \
|
|
--settings $APP_SETTINGS > /dev/null
|
|
printf "App settings configured.\n"
|
|
}
|
|
|
|
function create_federated_identity_credentials() {
|
|
printf "Creating federated identity credentials...\n"
|
|
EXISTING_CREDENTIAL_SUBJECTS=$(az rest --method GET --uri "https://graph.microsoft.com/beta/applications/$AAD_OBJECT_ID/federatedIdentityCredentials" -o json | jq -r '.value[].subject')
|
|
if [[ "$EXISTING_CREDENTIAL_SUBJECTS" == *"$WEBAPP_IDENTITY_OBJECT_ID"* ]]; then
|
|
echo "Federated identity credential already exists for the subject: $WEBAPP_IDENTITY_OBJECT_ID"
|
|
else
|
|
az webapp auth update \
|
|
--name $WEB_APP \
|
|
--resource-group $RESOURCE_GROUP \
|
|
--enabled true \
|
|
--action LoginWithAzureActiveDirectory \
|
|
--aad-client-id $AAD_CLIENT_ID \
|
|
--aad-token-issuer-url $AAD_TOKEN_ISSUER_URL > /dev/null
|
|
az rest --method POST \
|
|
--uri "https://graph.microsoft.com/beta/applications/$AAD_OBJECT_ID/federatedIdentityCredentials" \
|
|
--body "{'name': '$WEB_APP', 'issuer': '$AAD_TOKEN_ISSUER_URL', 'subject': '$WEBAPP_IDENTITY_OBJECT_ID', 'audiences': [ 'api://AzureADTokenExchange' ]}" > /dev/null
|
|
fi
|
|
printf "Federated identity credentials created.\n"
|
|
}
|
|
|
|
function configure_auth_settings() {
|
|
printf "Configuring auth settings...\n"
|
|
az webapp config appsettings set --resource-group $RESOURCE_GROUP \
|
|
--name $WEB_APP \
|
|
--slot-settings OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID=$WEBAPP_IDENTITY_CLIENT_ID \
|
|
--verbose > /dev/null
|
|
az webapp config appsettings list --resource-group $RESOURCE_GROUP \
|
|
--name $WEB_APP > /dev/null
|
|
|
|
authSettings=$(az rest --method GET --url "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Web/sites/$WEB_APP/config/authsettingsV2/list?api-version=2020-12-01" --output json)
|
|
echo $authSettings > auth.json
|
|
jq '.properties.identityProviders.azureActiveDirectory.registration.clientSecretSettingName = "OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID"' auth.json > tmp.json && mv tmp.json auth.json # pragma: allowlist secret
|
|
az rest --method PUT \
|
|
--url "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Web/sites/$WEB_APP/config/authsettingsV2?api-version=2020-12-01" \
|
|
--body @auth.json \
|
|
--headers "Content-Type=application/json" > /dev/null
|
|
rm auth.json
|
|
printf "Auth settings configured.\n"
|
|
}
|
|
|
|
function update_appreg_redirect_uris() {
|
|
printf "Updating app registration redirect URIs...\n"
|
|
WEB_APP_URL=$(az webapp show --name $WEB_APP --resource-group $RESOURCE_GROUP --query defaultHostName --output tsv)
|
|
NEW_REDIRECT_URI=https://$WEB_APP_URL/.auth/login/aad/callback
|
|
# Fetch the current list of web redirect URIs
|
|
CURRENT_URIS=$(az ad app show --id $AAD_CLIENT_ID --query "web.redirectUris" --output tsv)
|
|
if ! echo "${CURRENT_URIS}" | grep -q "${NEW_REDIRECT_URI}"; then
|
|
az ad app update --id $AAD_CLIENT_ID --web-redirect-uris ${CURRENT_URIS[@]} "$NEW_REDIRECT_URI" > /dev/null
|
|
fi
|
|
printf "App registration redirect URIs updated.\n"
|
|
}
|
|
|
|
function restart_web_app() {
|
|
printf "Restarting web app...\n"
|
|
az webapp restart --name $WEB_APP --resource-group $RESOURCE_GROUP > /dev/null
|
|
printf "Waiting for webapp to restart, webapp might take a few minutes to load.....\n"
|
|
sleep 180
|
|
printf "Web app restarted. \n"
|
|
}
|
|
|
|
## The following function adds outbound vnet integration on the webapp so that the frontend container can access resources in the AKS cluster directly.
|
|
## This will create a new subnet named "frontend" in the backend resource group's vnet if it does not exist.
|
|
## This may not be needed in simplified backend architecture but useful for folks using a prior version of the accelerator that had a different network architecture.
|
|
# function add_vnet_integration() {
|
|
# VNET_NAME=$(az network vnet list --resource-group $BACKEND_RESOURCE_GROUP --query "[0].name" --output tsv)
|
|
# VNET_ID=$(az network vnet list --resource-group $BACKEND_RESOURCE_GROUP --query "[0].id" --output tsv)
|
|
# SUBNET_NAMES=$(az network vnet subnet list --resource-group $BACKEND_RESOURCE_GROUP --vnet-name $VNET_NAME --query "[].name" --output tsv)
|
|
# SUBNET_NAME="frontend"
|
|
# if [[ $SUBNET_NAMES == *$SUBNET_NAME* ]]; then
|
|
# echo "Subnet with name $SUBNET_NAME already exists"
|
|
# else
|
|
# echo "Subnet with name $SUBNET_NAME does not exist, creating one now."
|
|
# az network vnet subnet create --resource-group $BACKEND_RESOURCE_GROUP --vnet-name $VNET_NAME --name $SUBNET_NAME --address-prefixes 10.0.10.0/24
|
|
# fi
|
|
# az webapp vnet-integration add --name $WEB_APP --resource-group $RESOURCE_GROUP --vnet $VNET_ID --subnet $SUBNET_NAME
|
|
# }
|
|
|
|
function usage() {
|
|
echo
|
|
echo "Usage: bash $0 [-h] -p <frontend_deploy.parameters.json>"
|
|
echo "Description: Deployment script for the Frontend App for GraphRAG Solution Accelerator."
|
|
echo "options:"
|
|
echo " -h Print this help menu."
|
|
echo " -p A JSON file containing the deployment parameters (frontend_deploy.parameters.json)."
|
|
echo
|
|
}
|
|
|
|
function main() {
|
|
load_env_variables
|
|
populateRequiredParams $PARAMS_FILE
|
|
set_variables
|
|
create_resource_group
|
|
create_acr
|
|
build_and_push_image
|
|
create_app_service_plan
|
|
create_web_app_identity
|
|
configure_registry_credentials
|
|
create_web_app
|
|
configure_app_settings
|
|
create_federated_identity_credentials
|
|
configure_auth_settings
|
|
# add_vnet_integration
|
|
update_appreg_redirect_uris
|
|
restart_web_app
|
|
echo "**********Graphrag Frontend Web app deployment successful!**********"
|
|
echo "Please visit the webapp at https://$WEB_APP_URL"
|
|
echo "*******************************************************************"
|
|
}
|
|
|
|
# print usage if no arguments are supplied
|
|
[ $# -eq 0 ] && usage && exit 0
|
|
PARAMS_FILE=""
|
|
while getopts ":p:h" option; do
|
|
case "${option}" in
|
|
p)
|
|
PARAMS_FILE=${OPTARG}
|
|
;;
|
|
h | *)
|
|
usage
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
shift $((OPTIND-1))
|
|
# check if required arguments are supplied
|
|
if [ ! -f $PARAMS_FILE ]; then
|
|
echo "Error: invalid required argument."
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
main
|