-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[DEVOPS-263] Add ephemeral deployments workflow (#61)
<details open> <summary><a href="https://amuniversal.atlassian.net/browse/DEVOPS-263" title="DEVOPS-263" target="_blank">DEVOPS-263</a></summary> <br /> <table> <tr> <th>Summary</th> <td>Create workflow for deploying Azure Container Instances for ephemeral deployments</td> </tr> <tr> <th>Type</th> <td> <img alt="Story" src="https://amuniversal.atlassian.net/images/icons/issuetypes/story.png" /> Story </td> </tr> <tr> <th>Status</th> <td>In Progress</td> </tr> <tr> <th>Points</th> <td>N/A</td> </tr> <tr> <th>Labels</th> <td>-</td> </tr> </table> </details> <!-- do not remove this marker as it will break action-jira-linter's functionality. added_by_jira_lint --> --- <!-- We appreciate the effort for this pull request but before that please make sure you read the contribution guidelines, then fill out the blanks below. Please format the PR title appropriately based on the type of change: [<issue>]: <description> Where <issue> is the related Jira Issue Key. --> ## Description - Add ephemeral deployments workflow ## Related Issues <!-- List any related Jira issues here --> - Jira Issue: DEVOPS-263 - Testing environment: [![Ephemeral Deployments](https://github.com/Andrews-McMeel-Universal/puzzle-society_ui/actions/workflows/ephemeral-deployment.yml/badge.svg?branch=research%2FPUZSOC-5782%2Fephemeral-deployments)](https://github.com/Andrews-McMeel-Universal/puzzle-society_ui/actions/workflows/ephemeral-deployment.yml)
- Loading branch information
1 parent
8e80049
commit 754a51c
Showing
1 changed file
with
227 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
name: Ephemeral Deployment | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
environment: | ||
required: true | ||
type: string | ||
description: "Deploy Environment. This is used to pull in and set the github environment. Can be development, staging, or production." | ||
environmentKeyVault: | ||
required: false | ||
type: string | ||
description: "AKS Key vault." | ||
repositoryName: | ||
required: false | ||
type: string | ||
description: "GitHub Repository Name." | ||
default: "${{ github.event.repository.name }}" | ||
clusterResourceGroup: | ||
required: false | ||
type: string | ||
description: "Azure Resource Group." | ||
default: "AMU_EphemeralDeployments_RG" | ||
dockerFilePath: | ||
required: false | ||
type: string | ||
description: "Relative path to Dockerfile." | ||
default: "." | ||
dockerImageName: | ||
required: false | ||
type: string | ||
description: "Docker image name." | ||
default: "${{ github.event.repository.name }}" | ||
azureResourceLocation: | ||
required: false | ||
type: string | ||
description: "Location of resources in Azure" | ||
default: "centralus" | ||
secrets: | ||
azureCredentials: | ||
required: true | ||
registryHostName: | ||
required: true | ||
registryUserName: | ||
required: true | ||
registryPassword: | ||
required: true | ||
githubPAT: | ||
required: true | ||
|
||
env: | ||
githubPrBranch: ${{ github.head_ref }} | ||
githubPrTitle: ${{ github.event.pull_request.title }} | ||
githubPrDescription: ${{ github.event.pull_request.body }} | ||
|
||
jobs: | ||
prepare: | ||
name: Preparation Step | ||
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'ephemeral-deployment' || github.event_name == 'pull_request' && github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'ephemeral-deployment') }} | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Retrieve Jira ticket ID | ||
id: jira-ticket | ||
run: | | ||
PR_BRANCH=$(echo "${{ env.githubPrBranch }}" | grep -Eo "\b[A-Z][A-Z0-9_]+-[1-9][0-9]*") | ||
PR_TITLE=$(echo "${{ env.githubPrTitle }}" | grep -Eo "\b[A-Z][A-Z0-9_]+-[1-9][0-9]*") | ||
PR_DESC=$(echo "${{ env.githubPrDescription }}" | grep -Eo "\b[A-Z][A-Z0-9_]+-[1-9][0-9]*") | ||
for var in ${PR_BRANCH} ${PR_TITLE} ${PR_DESC}; do JIRA_TICKET_ID=$(echo $var | grep -E ".") && break ; done | ||
JIRA_TICKET_ID_LC=$(echo "${JIRA_TICKET_ID}" | tr '[:upper:]' '[:lower:]') | ||
echo "jiraTicketIdLc=${JIRA_TICKET_ID_LC}" >> $GITHUB_OUTPUT | ||
echo "jiraTicketId=${JIRA_TICKET_ID}" >> $GITHUB_OUTPUT | ||
- name: Fix repository name | ||
id: repository-name | ||
run: | | ||
REPOSITORY_NAME=$(echo "${{ inputs.repositoryName }}" | tr '[:upper:]' '[:lower:]' | tr "_" "-") | ||
echo "repositoryName=${REPOSITORY_NAME}" >> $GITHUB_OUTPUT | ||
outputs: | ||
jiraTicketId: ${{ steps.jira-ticket.outputs.jiraTicketId }} | ||
jiraTicketIdLc: ${{ steps.jira-ticket.outputs.jiraTicketIdLc }} | ||
repositoryName: ${{ steps.repository-name.outputs.repositoryName }} | ||
|
||
deploy: | ||
name: Deploy Azure Container Instance | ||
if: ${{ github.event.action == 'labeled' && github.event.label.name == 'ephemeral-deployment' || github.event_name == 'pull_request' && github.event.action != 'closed' && github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'ephemeral-deployment') }} | ||
needs: [prepare] | ||
runs-on: ubuntu-latest | ||
environment: | ||
name: ${{ needs.prepare.outputs.jiraTicketId }} | ||
url: ${{ steps.hostname.outputs.hostname }} | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v3 | ||
|
||
- name: Generate .env file from Azure Key Vaults | ||
uses: Andrews-McMeel-Universal/get-envs@v1 | ||
with: | ||
environment: ${{ inputs.environment }} | ||
azurecredentials: ${{ secrets.azureCredentials }} | ||
environmentKeyVault: ${{ inputs.environmentKeyVault }} | ||
|
||
- name: Set environment variables | ||
id: env-vars | ||
shell: bash | ||
run: | | ||
ENVIRONMENT_VARIABLES=$(tr "\n" " " < .env) | ||
TARGET_PORT=$(find . -iname "values.yaml" -exec grep "targetPort: " {} \; | awk -F ': ' '{print $2}' | uniq) | ||
echo "targetPort=${TARGET_PORT}" >> $GITHUB_OUTPUT | ||
echo "environmentVariables=${ENVIRONMENT_VARIABLES}" >> $GITHUB_OUTPUT | ||
- name: Generate build args from Azure Key Vaults | ||
shell: bash | ||
run: | | ||
ENVIRONMENT="${{ inputs.environment }}" | ||
REPOSITORY_NAME="${{ inputs.repositoryName }}" | ||
ENV_KEYVAULT_NAME="${{ inputs.environmentKeyVault }}" | ||
BUILDARG_PREDICATE="--build-arg" | ||
# Check if searching for key vaults by repository name or otherwise, if key vault name argument is given | ||
if [ -z "${ENV_KEYVAULT_NAME}" ]; then | ||
# Search for key vault using tags | ||
KEYVAULT_NAME=$(az keyvault list --query "[?tags.\"repository-name\" == '${REPOSITORY_NAME}' && tags.environment == '${ENVIRONMENT}'].name" --output tsv) | ||
else | ||
KEYVAULT_NAME="${ENV_KEYVAULT_NAME}" | ||
fi | ||
# Get key vault object | ||
KEYVAULT=$(az keyvault list --query "[?name == '${KEYVAULT_NAME}']" ) | ||
# Check if key vault exists | ||
if ! echo "${KEYVAULT}" | grep -Eq "\w"; then | ||
echo -e "${RED}Invalid value provided for 'KeyVaultName'. Please confirm a Key Vault exists under the name specified. Value provided: ${KEYVAULT_NAME}" | ||
exit 1 | ||
fi | ||
KEYVAULT_NAME="${KEYVAULT_NAME// /}" | ||
# Set secrets list | ||
SECRETS=$(az keyvault secret list --vault-name "${KEYVAULT_NAME}" --query "[?contentType == 'BuildArg Env' || contentType == 'BuildArg'].name" --output tsv) | ||
# Loop through secrets and add them to .env | ||
if echo "${SECRETS}" | grep -Eq "\w"; then | ||
while IFS= read -r SECRET; do | ||
# Convert to upper case snake case and remove quotes | ||
SECRET_NAME=$(echo "${SECRET}" | tr '[:upper:][:lower:]' '[:lower:][:upper:]' | tr "-" "_" | tr -d '"') | ||
# Get secret value and set it to the secret name | ||
SECRET_VALUE=$(az keyvault secret show --vault-name "${KEYVAULT_NAME}" -n "${SECRET}" --query "value" --output tsv) | ||
# Add secret to file | ||
BUILDARGS="${BUILDARGS} ${BUILDARG_PREDICATE} ${SECRET_NAME}=${SECRET_VALUE}" | ||
done < <(echo "${SECRETS[*]}") | ||
fi | ||
echo "buildArguments=${BUILDARGS}" >> $GITHUB_ENV | ||
- name: Login to Azure Container Registry | ||
uses: Azure/docker-login@v1 | ||
with: | ||
login-server: ${{ secrets.registryHostName }} | ||
username: ${{ secrets.registryUserName }} | ||
password: ${{ secrets.registryPassword }} | ||
|
||
- name: Build & Push Docker Image | ||
id: docker | ||
run: | | ||
docker build ${{ inputs.dockerFilePath }} ${{ env.buildArguments }} -t "${{ secrets.registryHostName }}/${{ inputs.dockerImageName }}:${{ needs.prepare.outputs.jiraTicketId }}" | ||
docker push -a "${{ secrets.registryHostName }}/${{ inputs.dockerImageName }}" | ||
- name: Deploy Azure Container App | ||
uses: azure/container-apps-deploy-action@v1 | ||
with: | ||
registryUrl: ${{ secrets.registryHostName }} | ||
registryUsername: ${{ secrets.registryUserName }} | ||
registryPassword: ${{ secrets.registryPassword }} | ||
imageToDeploy: ${{ secrets.registryHostName }}/${{ inputs.dockerImageName }}:${{ needs.prepare.outputs.jiraTicketId }} | ||
containerAppName: ${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }} | ||
resourceGroup: ${{ inputs.clusterResourceGroup }} | ||
targetPort: ${{ steps.env-vars.outputs.targetPort }} | ||
location: ${{ inputs.azureResourceLocation }} | ||
environmentVariables: ${{ steps.env-vars.outputs.environmentVariables }} | ||
ingress: external | ||
disableTelemetry: true | ||
|
||
- name: Get Container App Hostname | ||
id: hostname | ||
run: | | ||
HOSTNAME=$(az containerapp list --query "[?name == '${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }}'].properties.configuration.ingress.fqdn" -o tsv) | ||
echo "hostname=https://${HOSTNAME}" >> $GITHUB_OUTPUT | ||
- name: Update Next URL variables | ||
if: contains(steps.env-vars.outputs.environmentVariables, 'BASE_URL') | ||
run: | | ||
REPOSITORY_NAME=$(echo "${{ github.event.repository.name }}" | awk -F '_' '{print $1}' | tr -d "-") | ||
HOSTNAME="${{ steps.hostname.outputs.hostname }}" | ||
URL_VARS="" | ||
while IFS= read -r line; do | ||
var=$(echo "$line" | awk -F '=' '{print $1}' | sed "s|$|=${HOSTNAME}|g") | ||
URL_VARS+="$var " | ||
done < <(grep -E "localhost|${REPOSITORY_NAME}.com" .env) | ||
az containerapp update -n "${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }}" -g "${{ inputs.clusterResourceGroup }}" --set-env-vars "${URL_VARS}" | ||
destroy: | ||
name: Destroy Azure Container Instance | ||
if: ${{ github.event_name == 'pull_request' && github.event.action == 'closed' }} | ||
needs: [prepare] | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Login via Az module | ||
uses: azure/login@v1 | ||
with: | ||
creds: "${{ secrets.azureCredentials }}" | ||
|
||
- name: Delete Azure Resources | ||
run: | | ||
az containerapp delete --resource-group ${{ inputs.clusterResourceGroup }} --name ${{ needs.prepare.outputs.repositoryName }}-${{ needs.prepare.outputs.jiraTicketIdLc }} --yes | ||
az acr repository delete -n ${{ secrets.registryHostName }} --image ${{ inputs.dockerImageName }}:${{ needs.prepare.outputs.jiraTicketId }} --yes | ||
- name: Delete deployment environment | ||
uses: strumwolf/delete-deployment-environment@v2 | ||
with: | ||
token: ${{ secrets.githubPAT }} | ||
environment: ${{ needs.prepare.outputs.jiraTicketId }} | ||
ref: ${{ github.ref_name }} |