From 2d2acaeaedeb063c6caf711a086735028e72a668 Mon Sep 17 00:00:00 2001 From: "Priyanka Singhal (Persistent Systems Inc)" Date: Wed, 4 Dec 2024 21:08:31 +0530 Subject: [PATCH 1/6] unit test cases and one click deploy pipeline --- .github/workflows/deploy.yml | 253 +++++++++++++++++++++++++++++++++++ .github/workflows/tests.yml | 111 +++++++++++++++ 2 files changed, 364 insertions(+) create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..3a16967a --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,253 @@ +name: CI-Validate Deployment + +on: + push: + branches: + - main + schedule: + - cron: '0 6,18 * * *' # Runs at 6:00 AM and 6:00 PM GMT + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v3 + + - name: Setup Azure CLI + run: | + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + az --version # Verify installation + + - name: Login to Azure + run: | + az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} + # Check if service principal exists + az ad sp show --id ${{ secrets.AZURE_CLIENT_ID }} + + - name: Install Bicep CLI + run: az bicep install + + - name: Generate Unique Solution Prefix and Environment Name + id: generate_solution_prefix + run: | + set -e + COMMON_PART="pslc" + TIMESTAMP=$(date +%s) + UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 3) + UNIQUE_SOLUTION_PREFIX="${COMMON_PART}${UPDATED_TIMESTAMP}" + ENVIRONMENT_NAME="env-${UNIQUE_SOLUTION_PREFIX}" # Dynamically generated environment name + echo "SOLUTION_PREFIX=${UNIQUE_SOLUTION_PREFIX}" >> $GITHUB_ENV + echo "ENVIRONMENT_NAME=${ENVIRONMENT_NAME}" >> $GITHUB_ENV + echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}, ENVIRONMENT_NAME: ${ENVIRONMENT_NAME}" + + - name: Deploy Template at Subscription Level + id: deploy + run: | + set -e + echo "Deploying template at the subscription level...." + az deployment sub create \ + --location WestUS \ + --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ + --template-file infra/main.bicep \ + --parameters \ + authClientId=${{ secrets.AZURE_CLIENT_ID }} \ + authClientSecret=${{ secrets.AZURE_CLIENT_SECRET }} \ + environmentName=rg-env-pslc88 \ + location=NorthCentralUS \ + principalId=${{ secrets.AZURE_PRINCIPAL_ID }} # Added Principal ID + + - name: Update Web App Docker Configuration + run: | + set -e + echo "Updating the Web App to use the ACR Docker image..." + + # Use the dynamically generated web app name from the previous step + webapp_name=app-backend-6esreazijnwm4 + container_registry="byocgacontainerreg.azurecr.io" + image_name="webapp:dev" + + # Set up Web App with the correct ACR image + az webapp config container set \ + --name $webapp_name \ + --resource-group rg-env-pslc88 \ + --docker-custom-image-name "$container_registry/$image_name" \ + --docker-registry-server-url "https://$container_registry" \ + --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ + --query "containerSettings" \ + --output json + + - name: List KeyVaults and Store in Array + id: list_keyvaults + run: | + set -e + echo "Listing all KeyVaults in the subscription..." + + # Get the list of KeyVaults in the subscription + keyvaults=$(az resource list --resource-type "Microsoft.KeyVault/vaults" --query "[].name" -o tsv) + + if [ -z "$keyvaults" ]; then + echo "No KeyVaults found in the subscription." + echo "KEYVAULTS=[]" >> $GITHUB_ENV # If no KeyVaults found, set an empty array + else + echo "KeyVaults found: $keyvaults" + + # Format the list into an array with proper formatting (no trailing comma) + keyvault_array="[" + first=true + for kv in $keyvaults; do + if [ "$first" = true ]; then + keyvault_array="$keyvault_array\"$kv\"" + first=false + else + keyvault_array="$keyvault_array,\"$kv\"" + fi + done + keyvault_array="$keyvault_array]" + + # Output the formatted array and save it to the environment variable + echo "KEYVAULTS=$keyvault_array" >> $GITHUB_ENV + fi + + - name: Delete Bicep Deployment + if: success() + run: | + set -e + echo "Deleting the resources from the subscription..." + az deployment sub delete \ + --name ${{ env.SOLUTION_PREFIX }} \ + --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ + --no-wait + + - name: Wait for resource deletion to complete + run: | + # List of KeyVaults and additional resources + KEYVAULTS="${{ env.KEYVAULTS }}" + + # Remove the surrounding square brackets, if they exist + stripped_keyvaults=$(echo "$KEYVAULTS" | sed 's/\[\|\]//g') + + # Convert the comma-separated string into an array + IFS=',' read -r -a resources_to_check <<< "$stripped_keyvaults" + + # Append new resources to the array + resources_to_check+=("${{ env.SOLUTION_PREFIX }}-openai" "${{ env.SOLUTION_PREFIX }}-cogser") + + echo "List of resources to check: ${resources_to_check[@]}" + + # Get the list of resources in YAML format + resource_list=$(az resource list --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} --output yaml) + + # Maximum number of retries + max_retries=3 + + # Retry intervals in seconds (30, 60, 120) + retry_intervals=(30 60 120) + + # Retry mechanism to check resources + retries=0 + while true; do + resource_found=false + + # Iterate through the resources to check + for resource in "${resources_to_check[@]}"; do + echo "Checking resource: $resource" + if echo "$resource_list" | grep -q "name: $resource"; then + echo "Resource '$resource' exists in the subscription." + resource_found=true + else + echo "Resource '$resource' does not exist in the subscription." + fi + done + + # If any resource exists, retry + if [ "$resource_found" = true ]; then + retries=$((retries + 1)) + if [ "$retries" -ge "$max_retries" ]; then + echo "Maximum retry attempts reached. Exiting." + break + else + # Wait for the appropriate interval for the current retry + echo "Waiting for ${retry_intervals[$retries-1]} seconds before retrying..." + sleep ${retry_intervals[$retries-1]} + fi + else + echo "No resources found. Exiting." + break + fi + done + + - name: Purging the Resources + if: success() + run: | + set -e + # Define variables + OPENAI_COMMON_PART="-openai" + openai_name="${{ env.SOLUTION_PREFIX }}${OPENAI_COMMON_PART}" + echo "Azure OpenAI: $openai_name" + + MULTISERVICE_COMMON_PART="-cogser" + multiservice_account_name="${{ env.SOLUTION_PREFIX }}${MULTISERVICE_COMMON_PART}" + echo "Azure MultiService Account: $multiservice_account_name" + + # Purge OpenAI Resource + echo "Purging the OpenAI Resource..." + if ! az resource delete --ids /subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.CognitiveServices/locations/uksouth/deletedAccounts/$openai_name --verbose; then + echo "Failed to purge openai resource: $openai_name" + else + echo "Purged the openai resource: $openai_name" + fi + + # Purge MultiService Account Resource + echo "Purging the MultiService Account Resource..." + if ! az resource delete --ids /subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.CognitiveServices/locations/uksouth/deletedAccounts/$multiservice_account_name --verbose; then + echo "Failed to purge multiService account resource: $multiservice_account_name" + else + echo "Purged the multiService account resource: $multiservice_account_name" + fi + + # Ensure KEYVAULTS is properly formatted as a comma-separated string + KEYVAULTS="${{ env.KEYVAULTS }}" + + # Remove the surrounding square brackets, if they exist + stripped_keyvaults=$(echo "$KEYVAULTS" | sed 's/\[\|\]//g') + + # Convert the comma-separated string into an array + IFS=',' read -r -a keyvault_array <<< "$stripped_keyvaults" + + echo "Using KeyVaults Array..." + for keyvault_name in "${keyvault_array[@]}"; do + echo "Processing KeyVault: $keyvault_name" + # Check if the KeyVault is soft-deleted + deleted_vaults=$(az keyvault list-deleted --query "[?name=='$keyvault_name']" -o json --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}) + + # If the KeyVault is found in the soft-deleted state, purge it + if [ "$(echo "$deleted_vaults" | jq length)" -gt 0 ]; then + echo "KeyVault '$keyvault_name' is soft-deleted. Proceeding to purge..." + az keyvault purge --name "$keyvault_name" --no-wait + else + echo "KeyVault '$keyvault_name' is not soft-deleted. No action taken." + fi + done + + echo "Resource purging completed successfully" + + - name: Send Notification on Failure + if: failure() + run: | + + RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + # Construct the email body + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the Client Advisor Automation process has encountered an issue and has failed to complete successfully.

Build URL: ${RUN_URL}
${OUTPUT}

Please investigate the matter at your earliest convenience.

Best regards,
Your Automation Team

" + } + EOF + ) + + # Send the notification + curl -X POST "${{ secrets.LOGIC_APP_URL }}" \ + -H "Content-Type: application/json" \ + -d "$EMAIL_BODY" || echo "Failed to send notification" \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..760261f8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,111 @@ +name: Tests + +on: + push: + branches: + - main # Trigger on push to the main branch + pull_request: + branches: + - main # Trigger on pull requests to the main branch + types: + - opened + - ready_for_review + - reopened + - synchronize + +jobs: + backend_tests: + name: Backend Tests + runs-on: ubuntu-latest # Use the latest Ubuntu runner + + steps: + - uses: actions/checkout@v4 # Checkout the repository + + # Set up Python environment for Backend + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" # Set Python version + + - name: Install Backend Dependencies + run: | + python -m pip install -r requirements.txt + python -m pip install coverage pytest-cov + python -m pip install azure-keyvault-secrets + + - name: Run Backend Tests with Coverage + run: | + if python -m pytest --cov=. --cov-report=xml --cov-report=html --cov-report=term-missing --junitxml=coverage-junit.xml; then + echo "Tests completed, checking coverage." + # Only fail if coverage does not meet criteria + if [ -f coverage.xml ]; then + COVERAGE=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); coverage = root.find('coverage').get('lines').split('%')[0]; print(float(coverage))") + if (( $(echo "$COVERAGE < 80" | bc -l) )); then + echo "Coverage is below 80%, failing the job." + exit 1 + fi + fi + else + echo "No tests found, skipping coverage check." + fi + + - uses: actions/upload-artifact@v4 + with: + name: backend-coverage + path: | + coverage.xml # Correct path to backend coverage + coverage-junit.xml # Correct path to backend JUnit report + htmlcov/ # Correct path to backend HTML coverage report + + frontend_tests: + name: Frontend Tests + runs-on: ubuntu-latest # Use the latest Ubuntu runner + + steps: + - uses: actions/checkout@v4 # Checkout the repository + + # Set up Node.js environment for Frontend + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: '20' # Set the Node.js version + + - name: Cache npm dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Navigate to frontend directory + run: cd frontend + + - name: Install Frontend Dependencies + run: | + cd frontend # Change to the frontend directory + npm install # Install dependencies from frontend/package.json + + - name: Run Frontend Tests with Coverage + run: | + cd frontend # Change to the frontend directory + if npm run test -- --coverage; then + echo "Tests completed, checking coverage." + # Check coverage report and ensure it meets threshold + if [ -f frontend/coverage/lcov-report/index.html ]; then + COVERAGE=$(cat frontend/coverage/lcov-report/index.html | grep -oP 'total: \K[0-9]+(\.[0-9]+)?') + if (( $(echo "$COVERAGE < 80" | bc -l) )); then + echo "Coverage is below 80%, failing the job." + exit 1 + fi + fi + else + echo "No tests found, skipping coverage check." + fi + + - uses: actions/upload-artifact@v4 + with: + name: frontend-coverage + path: | + frontend/coverage/ # Correct path to frontend coverage + frontend/coverage/lcov-report/ # Correct path to frontend lcov report \ No newline at end of file From 41054c97d1b9540206931f89012ba4f44787c123 Mon Sep 17 00:00:00 2001 From: "Priyanka Singhal (Persistent Systems Inc)" Date: Wed, 4 Dec 2024 22:43:07 +0530 Subject: [PATCH 2/6] changes in deployment file --- .github/workflows/deploy.yml | 47 ++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3a16967a..fd7057e7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,11 +1,17 @@ name: CI-Validate Deployment on: - push: - branches: - - main - schedule: - - cron: '0 6,18 * * *' # Runs at 6:00 AM and 6:00 PM GMT + push: + branches: + - main # Trigger on push to the main branch + pull_request: + branches: + - main # Trigger on pull requests to the main branch + types: + - opened + - ready_for_review + - reopened + - synchronize jobs: deploy: @@ -42,41 +48,47 @@ jobs: echo "ENVIRONMENT_NAME=${ENVIRONMENT_NAME}" >> $GITHUB_ENV echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}, ENVIRONMENT_NAME: ${ENVIRONMENT_NAME}" - - name: Deploy Template at Subscription Level + - name: Deploy Bicep Template at Subscription Level id: deploy run: | set -e - echo "Deploying template at the subscription level...." - az deployment sub create \ + echo "Deploying bicep template at the subscription level...." + deployment_output=$(az deployment sub create \ --location WestUS \ --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ --template-file infra/main.bicep \ --parameters \ authClientId=${{ secrets.AZURE_CLIENT_ID }} \ authClientSecret=${{ secrets.AZURE_CLIENT_SECRET }} \ - environmentName=rg-env-pslc88 \ + environmentName=${{ env.ENVIRONMENT_NAME }} \ location=NorthCentralUS \ - principalId=${{ secrets.AZURE_PRINCIPAL_ID }} # Added Principal ID + principalId=${{ secrets.AZURE_PRINCIPAL_ID }} \ + --query "properties.outputs.webappName.value" --output json) + + # Extract the webapp name from JSON response using jq + webapp_name=$(echo $deployment_output | jq -r .) + echo "webapp_name=$webapp_name" >> $GITHUB_ENV + echo "Deployment completed with webapp_name: $webapp_name" - name: Update Web App Docker Configuration run: | set -e echo "Updating the Web App to use the ACR Docker image..." - - # Use the dynamically generated web app name from the previous step - webapp_name=app-backend-6esreazijnwm4 + + # Use the dynamically retrieved web app name from the deployment step + webapp_name=${{ env.webapp_name }} container_registry="byocgacontainerreg.azurecr.io" image_name="webapp:dev" # Set up Web App with the correct ACR image az webapp config container set \ --name $webapp_name \ - --resource-group rg-env-pslc88 \ + --resource-group rg-${{ env.ENVIRONMENT_NAME }} \ --docker-custom-image-name "$container_registry/$image_name" \ --docker-registry-server-url "https://$container_registry" \ --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ --query "containerSettings" \ - --output json + --output json - name: List KeyVaults and Store in Array id: list_keyvaults @@ -109,7 +121,7 @@ jobs: # Output the formatted array and save it to the environment variable echo "KEYVAULTS=$keyvault_array" >> $GITHUB_ENV fi - + - name: Delete Bicep Deployment if: success() run: | @@ -236,7 +248,6 @@ jobs: - name: Send Notification on Failure if: failure() run: | - RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" # Construct the email body @@ -250,4 +261,4 @@ jobs: # Send the notification curl -X POST "${{ secrets.LOGIC_APP_URL }}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send notification" \ No newline at end of file + -d "$EMAIL_BODY" || echo "Failed to send notification" From 1a51871767c01bd33656b049c94a8fb38320bdbc Mon Sep 17 00:00:00 2001 From: "Priyanka Singhal (Persistent Systems Inc)" Date: Wed, 4 Dec 2024 23:36:22 +0530 Subject: [PATCH 3/6] added output in main.bicep --- .github/workflows/deploy.yml | 2 +- infra/main.bicep | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index fd7057e7..98eb5979 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -128,7 +128,7 @@ jobs: set -e echo "Deleting the resources from the subscription..." az deployment sub delete \ - --name ${{ env.SOLUTION_PREFIX }} \ + --name rg-${{ env.ENVIRONMENT_NAME }} \ --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ --no-wait diff --git a/infra/main.bicep b/infra/main.bicep index ee0c9826..334135ac 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -306,3 +306,4 @@ output AZURE_COSMOSDB_DATABASE string = cosmos.outputs.databaseName output AZURE_COSMOSDB_CONVERSATIONS_CONTAINER string = cosmos.outputs.containerName output AUTH_ISSUER_URI string = authIssuerUri +output webappName string = appServiceName From a5e164cd1bb10a423a1e760d4e2b97ed0ea709f5 Mon Sep 17 00:00:00 2001 From: "Priyanka Singhal (Persistent Systems Inc)" Date: Thu, 5 Dec 2024 00:04:28 +0530 Subject: [PATCH 4/6] scheduled the pipeline at 6 AM and 6 PM GMT --- .github/workflows/deploy.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 98eb5979..9355a970 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -3,15 +3,9 @@ name: CI-Validate Deployment on: push: branches: - - main # Trigger on push to the main branch - pull_request: - branches: - - main # Trigger on pull requests to the main branch - types: - - opened - - ready_for_review - - reopened - - synchronize + - main + schedule: + - cron: '0 6,18 * * *' # Runs at 6:00 AM and 6:00 PM GMT jobs: deploy: From b59e9a914150c749f43edc47cb753bfc5bc297d1 Mon Sep 17 00:00:00 2001 From: "Priyanka Singhal (Persistent Systems Inc)" Date: Mon, 9 Dec 2024 21:17:30 +0530 Subject: [PATCH 5/6] validated through deployment.json --- .github/workflows/deploy.yml | 254 +++++++++++++---------------------- infra/main.bicep | 1 - 2 files changed, 93 insertions(+), 162 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9355a970..5a43fd8b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,7 +10,6 @@ on: jobs: deploy: runs-on: ubuntu-latest - steps: - name: Checkout Code uses: actions/checkout@v3 @@ -23,139 +22,84 @@ jobs: - name: Login to Azure run: | az login --service-principal -u ${{ secrets.AZURE_CLIENT_ID }} -p ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} - # Check if service principal exists - az ad sp show --id ${{ secrets.AZURE_CLIENT_ID }} - name: Install Bicep CLI run: az bicep install - - name: Generate Unique Solution Prefix and Environment Name + - name: Generate Resource Group Name + id: generate_rg_name + run: | + echo "Generating a unique resource group name..." + TIMESTAMP=$(date +%Y%m%d%H%M%S) + COMMON_PART="pslautomationRes" + UNIQUE_RG_NAME="${COMMON_PART}${TIMESTAMP}" + echo "RESOURCE_GROUP_NAME=${UNIQUE_RG_NAME}" >> $GITHUB_ENV + echo "Generated Resource_GROUP_PREFIX: ${UNIQUE_RG_NAME}" + + - name: Check and Create Resource Group + id: check_create_rg + run: | + set -e + echo "Checking if resource group exists..." + rg_exists=$(az group exists --name ${{ env.RESOURCE_GROUP_NAME }}) + if [ "$rg_exists" = "false" ]; then + echo "Resource group does not exist. Creating..." + az group create --name ${{ env.RESOURCE_GROUP_NAME }} --location northcentralus || { echo "Error creating resource group"; exit 1; } + else + echo "Resource group already exists." + fi + + - name: Generate Unique Solution Prefix id: generate_solution_prefix run: | set -e - COMMON_PART="pslc" + COMMON_PART="pslr" TIMESTAMP=$(date +%s) UPDATED_TIMESTAMP=$(echo $TIMESTAMP | tail -c 3) UNIQUE_SOLUTION_PREFIX="${COMMON_PART}${UPDATED_TIMESTAMP}" - ENVIRONMENT_NAME="env-${UNIQUE_SOLUTION_PREFIX}" # Dynamically generated environment name echo "SOLUTION_PREFIX=${UNIQUE_SOLUTION_PREFIX}" >> $GITHUB_ENV - echo "ENVIRONMENT_NAME=${ENVIRONMENT_NAME}" >> $GITHUB_ENV - echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}, ENVIRONMENT_NAME: ${ENVIRONMENT_NAME}" + echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}" - - name: Deploy Bicep Template at Subscription Level + - name: Deploy Bicep Template id: deploy run: | set -e - echo "Deploying bicep template at the subscription level...." - deployment_output=$(az deployment sub create \ - --location WestUS \ - --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ - --template-file infra/main.bicep \ + az deployment group create \ + --resource-group ${{ env.RESOURCE_GROUP_NAME }} \ + --template-file infrastructure/deployment.json \ --parameters \ - authClientId=${{ secrets.AZURE_CLIENT_ID }} \ - authClientSecret=${{ secrets.AZURE_CLIENT_SECRET }} \ - environmentName=${{ env.ENVIRONMENT_NAME }} \ - location=NorthCentralUS \ - principalId=${{ secrets.AZURE_PRINCIPAL_ID }} \ - --query "properties.outputs.webappName.value" --output json) - - # Extract the webapp name from JSON response using jq - webapp_name=$(echo $deployment_output | jq -r .) - echo "webapp_name=$webapp_name" >> $GITHUB_ENV - echo "Deployment completed with webapp_name: $webapp_name" - - - name: Update Web App Docker Configuration + HostingPlanName="${{ env.SOLUTION_PREFIX }}-plan" \ + ApplicationInsightsName="appins-${{ env.SOLUTION_PREFIX }}" \ + WebsiteName="webapp-${{ env.SOLUTION_PREFIX }}" \ + CosmosDBName="db-cosmos-${{ env.SOLUTION_PREFIX }}" \ + CosmosDBRegion="NorthCentralUS" \ + AzureSearchService="search-${{ env.SOLUTION_PREFIX }}" \ + AzureOpenAIResource="aoai-${{ env.SOLUTION_PREFIX }}" \ + WorkspaceName="worksp-${{ env.SOLUTION_PREFIX }}" + + - name: Wait for Resource Deletion to Complete run: | - set -e - echo "Updating the Web App to use the ACR Docker image..." - - # Use the dynamically retrieved web app name from the deployment step - webapp_name=${{ env.webapp_name }} - container_registry="byocgacontainerreg.azurecr.io" - image_name="webapp:dev" - - # Set up Web App with the correct ACR image - az webapp config container set \ - --name $webapp_name \ - --resource-group rg-${{ env.ENVIRONMENT_NAME }} \ - --docker-custom-image-name "$container_registry/$image_name" \ - --docker-registry-server-url "https://$container_registry" \ - --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ - --query "containerSettings" \ - --output json - - - name: List KeyVaults and Store in Array - id: list_keyvaults - run: | - set -e - echo "Listing all KeyVaults in the subscription..." - - # Get the list of KeyVaults in the subscription - keyvaults=$(az resource list --resource-type "Microsoft.KeyVault/vaults" --query "[].name" -o tsv) - - if [ -z "$keyvaults" ]; then - echo "No KeyVaults found in the subscription." - echo "KEYVAULTS=[]" >> $GITHUB_ENV # If no KeyVaults found, set an empty array - else - echo "KeyVaults found: $keyvaults" - - # Format the list into an array with proper formatting (no trailing comma) - keyvault_array="[" - first=true - for kv in $keyvaults; do - if [ "$first" = true ]; then - keyvault_array="$keyvault_array\"$kv\"" - first=false - else - keyvault_array="$keyvault_array,\"$kv\"" - fi - done - keyvault_array="$keyvault_array]" - - # Output the formatted array and save it to the environment variable - echo "KEYVAULTS=$keyvault_array" >> $GITHUB_ENV - fi - - - name: Delete Bicep Deployment - if: success() - run: | - set -e - echo "Deleting the resources from the subscription..." - az deployment sub delete \ - --name rg-${{ env.ENVIRONMENT_NAME }} \ - --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} \ - --no-wait - - - name: Wait for resource deletion to complete - run: | - # List of KeyVaults and additional resources - KEYVAULTS="${{ env.KEYVAULTS }}" - - # Remove the surrounding square brackets, if they exist - stripped_keyvaults=$(echo "$KEYVAULTS" | sed 's/\[\|\]//g') - - # Convert the comma-separated string into an array - IFS=',' read -r -a resources_to_check <<< "$stripped_keyvaults" - - # Append new resources to the array - resources_to_check+=("${{ env.SOLUTION_PREFIX }}-openai" "${{ env.SOLUTION_PREFIX }}-cogser") - - echo "List of resources to check: ${resources_to_check[@]}" + # List of resources to check based on SOLUTION_PREFIX + resources_to_check=( + "aoai-${{ env.SOLUTION_PREFIX }}" + "appins-${{ env.SOLUTION_PREFIX }}" + "db-cosmos-${{ env.SOLUTION_PREFIX }}" + "${{ env.SOLUTION_PREFIX }}-plan" + "search-${{ env.SOLUTION_PREFIX }}" + "webapp-${{ env.SOLUTION_PREFIX }}" + "worksp-${{ env.SOLUTION_PREFIX }}" + ) # Get the list of resources in YAML format resource_list=$(az resource list --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} --output yaml) - - # Maximum number of retries + + # Maximum number of retries and retry intervals max_retries=3 - - # Retry intervals in seconds (30, 60, 120) retry_intervals=(30 60 120) - - # Retry mechanism to check resources retries=0 + while true; do resource_found=false - # Iterate through the resources to check for resource in "${resources_to_check[@]}"; do echo "Checking resource: $resource" @@ -174,7 +118,6 @@ jobs: echo "Maximum retry attempts reached. Exiting." break else - # Wait for the appropriate interval for the current retry echo "Waiting for ${retry_intervals[$retries-1]} seconds before retrying..." sleep ${retry_intervals[$retries-1]} fi @@ -187,72 +130,61 @@ jobs: - name: Purging the Resources if: success() run: | - set -e - # Define variables - OPENAI_COMMON_PART="-openai" - openai_name="${{ env.SOLUTION_PREFIX }}${OPENAI_COMMON_PART}" - echo "Azure OpenAI: $openai_name" - - MULTISERVICE_COMMON_PART="-cogser" - multiservice_account_name="${{ env.SOLUTION_PREFIX }}${MULTISERVICE_COMMON_PART}" - echo "Azure MultiService Account: $multiservice_account_name" - - # Purge OpenAI Resource - echo "Purging the OpenAI Resource..." - if ! az resource delete --ids /subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.CognitiveServices/locations/uksouth/deletedAccounts/$openai_name --verbose; then - echo "Failed to purge openai resource: $openai_name" - else - echo "Purged the openai resource: $openai_name" - fi - - # Purge MultiService Account Resource - echo "Purging the MultiService Account Resource..." - if ! az resource delete --ids /subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.CognitiveServices/locations/uksouth/deletedAccounts/$multiservice_account_name --verbose; then - echo "Failed to purge multiService account resource: $multiservice_account_name" - else - echo "Purged the multiService account resource: $multiservice_account_name" - fi - - # Ensure KEYVAULTS is properly formatted as a comma-separated string - KEYVAULTS="${{ env.KEYVAULTS }}" - - # Remove the surrounding square brackets, if they exist - stripped_keyvaults=$(echo "$KEYVAULTS" | sed 's/\[\|\]//g') + set -e + # Purging resources based on solution prefix + echo "Purging resources..." + + # List of resources to purge + resources_to_purge=( + "aoai-${{ env.SOLUTION_PREFIX }}" + "appins-${{ env.SOLUTION_PREFIX }}" + "db-cosmos-${{ env.SOLUTION_PREFIX }}" + "${{ env.SOLUTION_PREFIX }}-plan" + "search-${{ env.SOLUTION_PREFIX }}" + "webapp-${{ env.SOLUTION_PREFIX }}" + "worksp-${{ env.SOLUTION_PREFIX }}" + ) - # Convert the comma-separated string into an array - IFS=',' read -r -a keyvault_array <<< "$stripped_keyvaults" - - echo "Using KeyVaults Array..." - for keyvault_name in "${keyvault_array[@]}"; do - echo "Processing KeyVault: $keyvault_name" - # Check if the KeyVault is soft-deleted - deleted_vaults=$(az keyvault list-deleted --query "[?name=='$keyvault_name']" -o json --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }}) - - # If the KeyVault is found in the soft-deleted state, purge it - if [ "$(echo "$deleted_vaults" | jq length)" -gt 0 ]; then - echo "KeyVault '$keyvault_name' is soft-deleted. Proceeding to purge..." - az keyvault purge --name "$keyvault_name" --no-wait + for resource in "${resources_to_purge[@]}"; do + echo "Purging resource: $resource" + if ! az resource delete --ids /subscriptions/${{ secrets.AZURE_SUBSCRIPTION_ID }}/providers/Microsoft.CognitiveServices/locations/uksouth/deletedAccounts/$resource --verbose; then + echo "Failed to purge resource: $resource" else - echo "KeyVault '$keyvault_name' is not soft-deleted. No action taken." + echo "Purged the resource: $resource" fi done echo "Resource purging completed successfully" - + + - name: Delete Bicep Deployment + if: success() + run: | + set -e + echo "Checking if resource group exists..." + rg_exists=$(az group exists --name ${{ env.RESOURCE_GROUP_NAME }}) + if [ "$rg_exists" = "true" ]; then + echo "Resource group exists. Cleaning..." + az group delete \ + --name ${{ env.RESOURCE_GROUP_NAME }} \ + --yes \ + --no-wait + echo "Resource group deleted... ${{ env.RESOURCE_GROUP_NAME }}" + else + echo "Resource group does not exist." + fi + - name: Send Notification on Failure if: failure() run: | RUN_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - # Construct the email body + EMAIL_BODY=$(cat <Dear Team,

We would like to inform you that the Client Advisor Automation process has encountered an issue and has failed to complete successfully.

Build URL: ${RUN_URL}
${OUTPUT}

Please investigate the matter at your earliest convenience.

Best regards,
Your Automation Team

" + "body": "

Dear Team,

We would like to inform you that the Research Assistant Automation process has encountered an issue and has failed to complete successfully.

Build URL: ${RUN_URL}
${OUTPUT}

Please investigate the matter at your earliest convenience.

Best regards,
Your Automation Team

" } EOF ) - - # Send the notification + curl -X POST "${{ secrets.LOGIC_APP_URL }}" \ -H "Content-Type: application/json" \ -d "$EMAIL_BODY" || echo "Failed to send notification" diff --git a/infra/main.bicep b/infra/main.bicep index 334135ac..ee0c9826 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -306,4 +306,3 @@ output AZURE_COSMOSDB_DATABASE string = cosmos.outputs.databaseName output AZURE_COSMOSDB_CONVERSATIONS_CONTAINER string = cosmos.outputs.containerName output AUTH_ISSUER_URI string = authIssuerUri -output webappName string = appServiceName From ee9be99d0fe827b6fbdfc0ac29c072f4dab9db43 Mon Sep 17 00:00:00 2001 From: "Priyanka Singhal (Persistent Systems Inc)" Date: Tue, 10 Dec 2024 17:48:34 +0530 Subject: [PATCH 6/6] Validated deleting the main resource group --- .github/workflows/deploy.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5a43fd8b..29d3e5f3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -76,6 +76,23 @@ jobs: AzureSearchService="search-${{ env.SOLUTION_PREFIX }}" \ AzureOpenAIResource="aoai-${{ env.SOLUTION_PREFIX }}" \ WorkspaceName="worksp-${{ env.SOLUTION_PREFIX }}" + + - name: Delete Bicep Deployment + if: success() + run: | + set -e + echo "Checking if resource group exists..." + rg_exists=$(az group exists --name ${{ env.RESOURCE_GROUP_NAME }}) + if [ "$rg_exists" = "true" ]; then + echo "Resource group exists. Cleaning..." + az group delete \ + --name ${{ env.RESOURCE_GROUP_NAME }} \ + --yes \ + --no-wait + echo "Resource group deleted... ${{ env.RESOURCE_GROUP_NAME }}" + else + echo "Resource group does not exist." + fi - name: Wait for Resource Deletion to Complete run: | @@ -156,23 +173,6 @@ jobs: echo "Resource purging completed successfully" - - name: Delete Bicep Deployment - if: success() - run: | - set -e - echo "Checking if resource group exists..." - rg_exists=$(az group exists --name ${{ env.RESOURCE_GROUP_NAME }}) - if [ "$rg_exists" = "true" ]; then - echo "Resource group exists. Cleaning..." - az group delete \ - --name ${{ env.RESOURCE_GROUP_NAME }} \ - --yes \ - --no-wait - echo "Resource group deleted... ${{ env.RESOURCE_GROUP_NAME }}" - else - echo "Resource group does not exist." - fi - - name: Send Notification on Failure if: failure() run: | @@ -187,4 +187,4 @@ jobs: curl -X POST "${{ secrets.LOGIC_APP_URL }}" \ -H "Content-Type: application/json" \ - -d "$EMAIL_BODY" || echo "Failed to send notification" + -d "$EMAIL_BODY" || echo "Failed to send notification" \ No newline at end of file