diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 08e79aa0..48504204 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -2,243 +2,250 @@ name: Validate Deployment on: push: branches: - - main # Adjust this to the branch you want to trigger the deployment on + - main # Adjust this to the branch you want to trigger the deployment on - dev - demo schedule: - - cron: '0 10,22 * * *' # Runs at 10:00 AM and 10:00 PM GMT - + - cron: "0 10,22 * * *" # Runs at 10:00 AM and 10:00 PM GMT jobs: deploy: - runs-on: windows-latest # Use a Windows runner for PowerShell scripts + runs-on: windows-latest # Use a Windows runner for PowerShell scripts steps: - - name: Checkout Code - uses: actions/checkout@v4 # Checks out your repository - # Install Azure CLI - - name: Install Azure CLI - shell: pwsh - run: | + - name: Checkout Code + uses: actions/checkout@v4 # Checks out your repository + # Install Azure CLI + - name: Install Azure CLI + shell: pwsh + run: | Invoke-WebRequest -Uri https://aka.ms/installazurecliwindows -OutFile AzureCLI.msi Start-Process msiexec.exe -ArgumentList '/I AzureCLI.msi /quiet' -Wait - # Install kubectl (Windows method) - - name: Install kubectl - shell: pwsh - run: | - Invoke-WebRequest -Uri https://dl.k8s.io/release/v1.28.0/bin/windows/amd64/kubectl.exe -OutFile kubectl.exe - Move-Item -Path ./kubectl.exe -Destination "C:\kubectl.exe" - [Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\', [System.EnvironmentVariableTarget]::Machine) - + # Install kubectl (Windows method) + - name: Install kubectl + shell: pwsh + run: | + Invoke-WebRequest -Uri https://dl.k8s.io/release/v1.28.0/bin/windows/amd64/kubectl.exe -OutFile kubectl.exe + Move-Item -Path ./kubectl.exe -Destination "C:\kubectl.exe" + [Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\', [System.EnvironmentVariableTarget]::Machine) - # Install Helm (Windows method) - - name: Install Helm - shell: pwsh - run: | + # Install Helm (Windows method) + - name: Install Helm + shell: pwsh + run: | Invoke-WebRequest -Uri https://get.helm.sh/helm-v3.13.0-windows-amd64.zip -OutFile helm.zip Expand-Archive helm.zip -DestinationPath helm Move-Item -Path ./helm/windows-amd64/helm.exe -Destination "C:\helm.exe" [Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\', [System.EnvironmentVariableTarget]::Machine) - - - name: Set Docker environment variables - run: echo "DOCKER_BUILDKIT=0" >> $GITHUB_ENV - - # Set up Docker - - name: Set up Docker - uses: docker/setup-buildx-action@v3 - with: - driver: docker - - - name: Setup PowerShell - shell: pwsh - run: | - $PSVersionTable.PSVersion - - # Run Quota Check Script - - name: Run Quota Check - id: quota-check - shell: pwsh - run: | - $ErrorActionPreference = "Stop" # Ensure that any error stops the pipeline + - name: Set Docker environment variables + run: echo "DOCKER_BUILDKIT=0" >> $GITHUB_ENV + + # Set up Docker + - name: Set up Docker + uses: docker/setup-buildx-action@v3 + with: + driver: docker + + - name: Setup PowerShell + shell: pwsh + run: | + $PSVersionTable.PSVersion + + # Run Quota Check Script + - name: Run Quota Check + id: quota-check + shell: pwsh + run: | + $ErrorActionPreference = "Stop" # Ensure that any error stops the pipeline + + # Path to the PowerShell script for quota check + $quotaCheckScript = "Deployment/checkquota.ps1" + + # Check if the script exists and is executable (not needed for PowerShell like chmod) + if (-not (Test-Path $quotaCheckScript)) { + Write-Host "❌ Error: Quota check script not found." + exit 1 + } + + # Run the script + .\Deployment\checkquota.ps1 + + # If the script fails, check for the failure message + $quotaFailedMessage = "No region with sufficient quota found" + $output = Get-Content "Deployment/checkquota.ps1" + + if ($output -contains $quotaFailedMessage) { + echo "QUOTA_FAILED=true" >> $GITHUB_ENV + } + env: + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + GPT_MIN_CAPACITY: "10" + TEXT_EMBEDDING_MIN_CAPACITY: "10" + AZURE_REGIONS: "${{ vars.AZURE_REGIONS }}" + + # Send Notification on Quota Failure + - name: Send Notification on Quota Failure + if: env.QUOTA_FAILED == 'true' + shell: pwsh + run: | + $RUN_URL = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + # Construct the email body + $EMAIL_BODY = @" + { + "body": "

Dear Team,

The quota check has failed, and the pipeline cannot proceed.

Build URL: $RUN_URL

Please take necessary action.

Best regards,
Your Automation Team

" + } + "@ + + # Send the notification + try { + $response = Invoke-RestMethod -Uri "${{ secrets.LOGIC_APP_URL }}" -Method Post -ContentType "application/json" -Body $EMAIL_BODY + Write-Host "Notification sent successfully." + } catch { + Write-Host "❌ Failed to send notification." + } + + - name: Fail Pipeline if Quota Check Fails + if: env.QUOTA_FAILED == 'true' + run: exit 1 - # Path to the PowerShell script for quota check - $quotaCheckScript = "Deployment/checkquota.ps1" - - # Check if the script exists and is executable (not needed for PowerShell like chmod) - if (-not (Test-Path $quotaCheckScript)) { - Write-Host "❌ Error: Quota check script not found." - exit 1 - } - - # Run the script - .\Deployment\checkquota.ps1 - - # If the script fails, check for the failure message - $quotaFailedMessage = "No region with sufficient quota found" - $output = Get-Content "Deployment/checkquota.ps1" - - if ($output -contains $quotaFailedMessage) { - echo "QUOTA_FAILED=true" >> $GITHUB_ENV - } - env: - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - GPT_MIN_CAPACITY: '10' - TEXT_EMBEDDING_MIN_CAPACITY: '10' - AZURE_REGIONS: "${{ vars.AZURE_REGIONS }}" - - - # Send Notification on Quota Failure - - name: Send Notification on Quota Failure - if: env.QUOTA_FAILED == 'true' - shell: pwsh - run: | - $RUN_URL = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - # Construct the email body - $EMAIL_BODY = @" - { - "body": "

Dear Team,

The quota check has failed, and the pipeline cannot proceed.

Build URL: $RUN_URL

Please take necessary action.

Best regards,
Your Automation Team

" - } - "@ - - # Send the notification - try { - $response = Invoke-RestMethod -Uri "${{ secrets.LOGIC_APP_URL }}" -Method Post -ContentType "application/json" -Body $EMAIL_BODY - Write-Host "Notification sent successfully." - } catch { - Write-Host "❌ Failed to send notification." - } - - - name: Fail Pipeline if Quota Check Fails - if: env.QUOTA_FAILED == 'true' - run: exit 1 - - - name: Run Deployment Script with Input - shell: pwsh - run: | - cd Deployment - $input = @" - ${{ secrets.AZURE_SUBSCRIPTION_ID }} - CanadaCentral - ${{ env.VALID_REGION }} - ${{ secrets.EMAIL }} - yes - "@ - $input | pwsh ./resourcedeployment.ps1 - echo "Resource Group Name is ${{ env.rg_name }}" - echo "Kubernetes resource group are ${{ env.krg_name }}" - env: - AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - - name: Cleanup Resource Group - if: always() # Ensures this step runs even if the deployment fails - shell: pwsh - run: | + - name: Generate Environment Name + id: generate_environment_name + shell: bash + run: | + set -e + TIMESTAMP_SHORT=$(date +%s | tail -c 5) # Last 4-5 digits of epoch seconds + RANDOM_SUFFIX=$(head /dev/urandom | tr -dc 'a-z0-9' | head -c 8) # 8 random alphanum chars + UNIQUE_ENV_NAME="${TIMESTAMP_SHORT}${RANDOM_SUFFIX}" # Usually ~12-13 chars + echo "ENVIRONMENT_NAME=${UNIQUE_ENV_NAME}" >> $GITHUB_ENV + echo "Generated ENVIRONMENT_NAME: ${UNIQUE_ENV_NAME}" + + - name: Run Deployment Script with Input + shell: pwsh + run: | + cd Deployment + $input = @" + ${{ secrets.AZURE_SUBSCRIPTION_ID }} + ${{ env.ENVIRONMENT_NAME }} + + CanadaCentral + ${{ env.VALID_REGION }} + ${{ secrets.EMAIL }} + yes + "@ + $input | pwsh ./resourcedeployment.ps1 + echo "Resource Group Name is ${{ env.rg_name }}" + echo "Kubernetes resource group are ${{ env.krg_name }}" + env: + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + - name: Cleanup Resource Group + if: always() # Ensures this step runs even if the deployment fails + shell: pwsh + run: | az login --service-principal --username ${{ secrets.AZURE_CLIENT_ID }} --password ${{ secrets.AZURE_CLIENT_SECRET }} --tenant ${{ secrets.AZURE_TENANT_ID }} az group delete --name ${{ env.rg_name }} --yes --no-wait az group delete --name ${{ env.krg_name }} --yes --no-wait - env: + env: AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - - name: Wait for Resource Deletion to Complete - shell: pwsh - run: | - $retries = 0 - $maxRetries = 3 - $sleepIntervals = @(700, 200, 200) - - while ($retries -lt $maxRetries) { - $rgStatus = az group exists --name ${{ env.rg_name }} - $krgStatus = az group exists --name ${{ env.krg_name }} - - - # if (-not $rgStatus -and -not $krgStatus) { - # Write-Host "Both resource groups deleted successfully." - # break - # } - if ($rgStatus -eq "false" -and $krgStatus -eq "false") { - Write-Host "Both resource groups deleted successfully." - break + - name: Wait for Resource Deletion to Complete + shell: pwsh + run: | + $retries = 0 + $maxRetries = 3 + $sleepIntervals = @(700, 200, 200) + + while ($retries -lt $maxRetries) { + $rgStatus = az group exists --name ${{ env.rg_name }} + $krgStatus = az group exists --name ${{ env.krg_name }} + + + # if (-not $rgStatus -and -not $krgStatus) { + # Write-Host "Both resource groups deleted successfully." + # break + # } + if ($rgStatus -eq "false" -and $krgStatus -eq "false") { + Write-Host "Both resource groups deleted successfully." + break + } + + $retries++ + if ($retries -eq $maxRetries) { + Write-Host "Resource groups deletion not confirmed after $maxRetries attempts. Exiting." + exit 1 + } + + Write-Host "Resource groups still exist. Retrying in $($sleepIntervals[$retries - 1]) seconds..." + Start-Sleep -Seconds $sleepIntervals[$retries - 1] + } + + - name: Purging the Resources + if: success() + shell: pwsh + run: | + # Set variables using GitHub Actions environment values + $solutionPrefix = "${{ env.SOLUTION_PREFIX }}" + $subscriptionId = "${{ secrets.AZURE_SUBSCRIPTION_ID }}" + $resourceGroupName = "${{ env.rg_name }}" + + $openai_name = "openaiservice-$solutionPrefix" + $cognitiveservice_name = "cognitiveservice-$solutionPrefix" + + # Debug: Print resource names + Write-Host "Purging OpenAI resource: $openai_name" + Write-Host "Purging CognitiveService Account: $cognitiveservice_name" + + # Construct resource IDs + $openaiResourceId = "/subscriptions/$subscriptionId/providers/Microsoft.CognitiveServices/locations/${{ env.VALID_REGION }}/resourceGroups/$resourceGroupName/deletedAccounts/$openai_name" + $cognitiveResourceId = "/subscriptions/$subscriptionId/providers/Microsoft.CognitiveServices/locations/${{ env.VALID_REGION }}/resourceGroups/$resourceGroupName/deletedAccounts/$cognitiveservice_name" + + # Debug: Print constructed resource IDs + Write-Host "Command to purge OpenAI resource: az resource delete --ids `"$openaiResourceId`" --verbose" + Write-Host "Command to purge CognitiveService Account: az resource delete --ids `"$cognitiveResourceId`" --verbose" + # Purge OpenAI Resource + az resource delete --ids $openaiResourceId --verbose + if (-not $?) { + Write-Host "Failed to purge OpenAI resource: $openaiResourceId" } - - $retries++ - if ($retries -eq $maxRetries) { - Write-Host "Resource groups deletion not confirmed after $maxRetries attempts. Exiting." - exit 1 + + # Purge CognitiveService Account + + + az resource delete --ids $cognitiveResourceId --verbose + if (-not $?) { + Write-Host "Failed to purge CognitiveService Account." } - - Write-Host "Resource groups still exist. Retrying in $($sleepIntervals[$retries - 1]) seconds..." - Start-Sleep -Seconds $sleepIntervals[$retries - 1] - } - - - name: Purging the Resources - if: success() - shell: pwsh - run: | - # Set variables using GitHub Actions environment values - $solutionPrefix = "${{ env.SOLUTION_PREFIX }}" - $subscriptionId = "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - $resourceGroupName = "${{ env.rg_name }}" - - $openai_name = "openaiservice-$solutionPrefix" - $cognitiveservice_name = "cognitiveservice-$solutionPrefix" - - # Debug: Print resource names - Write-Host "Purging OpenAI resource: $openai_name" - Write-Host "Purging CognitiveService Account: $cognitiveservice_name" - - # Construct resource IDs - $openaiResourceId = "/subscriptions/$subscriptionId/providers/Microsoft.CognitiveServices/locations/${{ env.VALID_REGION }}/resourceGroups/$resourceGroupName/deletedAccounts/$openai_name" - $cognitiveResourceId = "/subscriptions/$subscriptionId/providers/Microsoft.CognitiveServices/locations/${{ env.VALID_REGION }}/resourceGroups/$resourceGroupName/deletedAccounts/$cognitiveservice_name" - - # Debug: Print constructed resource IDs - Write-Host "Command to purge OpenAI resource: az resource delete --ids `"$openaiResourceId`" --verbose" - Write-Host "Command to purge CognitiveService Account: az resource delete --ids `"$cognitiveResourceId`" --verbose" - # Purge OpenAI Resource - az resource delete --ids $openaiResourceId --verbose - if (-not $?) { - Write-Host "Failed to purge OpenAI resource: $openaiResourceId" - } - - # Purge CognitiveService Account - - - az resource delete --ids $cognitiveResourceId --verbose - if (-not $?) { - Write-Host "Failed to purge CognitiveService Account." - } - - - - name: Send Notification on Failure - if: failure() - shell: pwsh - run: | - # Define the RUN_URL variable - $RUN_URL = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - # Construct the email body using a Here-String - $EMAIL_BODY = @" - { - "body": "

Dear Team,

The Document Knowledge Mining Automation process encountered an issue.

Build URL: $RUN_URL

Please investigate promptly.

Best regards,
Your Automation Team

" - } - "@ - - # Send the notification with error handling - try { - curl -X POST "${{ secrets.LOGIC_APP_URL }}" ` - -H "Content-Type: application/json" ` - -d "$EMAIL_BODY" - } catch { - Write-Output "Failed to send notification." - } - + + - name: Send Notification on Failure + if: failure() + shell: pwsh + run: | + # Define the RUN_URL variable + $RUN_URL = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + + # Construct the email body using a Here-String + $EMAIL_BODY = @" + { + "body": "

Dear Team,

The Document Knowledge Mining Automation process encountered an issue.

Build URL: $RUN_URL

Please investigate promptly.

Best regards,
Your Automation Team

" + } + "@ + + # Send the notification with error handling + try { + curl -X POST "${{ secrets.LOGIC_APP_URL }}" ` + -H "Content-Type: application/json" ` + -d "$EMAIL_BODY" + } catch { + Write-Output "Failed to send notification." + }