Skip to content

Deploy a staging environment #1806

Deploy a staging environment

Deploy a staging environment #1806

name: Deploy a staging environment
on:
workflow_dispatch:
inputs:
manifest:
description: 'The manifest file to deploy (base64 encoded)'
required: true
type: string
sandbox-id:
description: 'The sandbox ID to deploy under'
required: true
type: string
with-rds:
description: 'Stage a new RDS instance'
required: false
default: 'False'
type: string
pipeline-pr:
description: Pipeline PR number to stage
required: false
default: ""
type: string
secrets:
description: 'Encrypted secrets to use for this task'
required: true
type: string
env:
region: ${{ secrets.AWS_REGION }}
permissions:
id-token: write
contents: read
jobs:
load-config:
uses: ./.github/workflows/load-config.yaml
deploy-staging:
name: Deploy staging environment
runs-on: ubuntu-20.04
needs: load-config
environment: ${{needs.load-config.outputs.domain_name}}
steps:
- id: setup-aws
name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/ci-iac-role
aws-region: ${{ env.region }}
- id: install-aws-cli
name: Install AWS CLI
uses: unfor19/install-aws-cli-action@v1
with:
version: 2
- id: checkout
name: Check out source code
uses: actions/checkout@v3
with:
token: ${{ secrets.API_TOKEN_GITHUB }}
- id: install-eksctl
name: Install eksctl
run: |-
curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv /tmp/eksctl /usr/local/bin
- id: set-stack-name
name: Set name of the CloudFormation stacks
run: |-
BASE_NAME=biomage-rds-staging-$SANDBOX_ID
echo "rds-name=$BASE_NAME" >> $GITHUB_OUTPUT
BASE_NAME=biomage-sns-staging-$SANDBOX_ID
echo "sns-name=$BASE_NAME" >> $GITHUB_OUTPUT
BASE_NAME=biomage-userpoolclient-staging-$SANDBOX_ID
echo "userpoolclient-name=$BASE_NAME" >> $GITHUB_OUTPUT
BASE_NAME=biomage-batch-job-definition-staging-$SANDBOX_ID
echo "batch-job-definition-name=$BASE_NAME" >> $GITHUB_OUTPUT
env:
SANDBOX_ID: ${{ github.event.inputs.sandbox-id }}
- id: create-worker-fargate-profile
name: Attempt to create worker Fargate profile
uses: nick-invision/retry@v2
with:
timeout_seconds: 900
max_attempts: 30
retry_on: error
command: |
output=$(eksctl create fargateprofile --cluster biomage-staging --region ${{ secrets.AWS_REGION }} --name worker-${SANDBOX_ID} --labels type=worker --namespace worker-${SANDBOX_ID} 2>&1)
echo $output
echo $output | grep "created Fargate profile"
# Add jitter to break up correlated events.
on_retry_command: sleep $((20 + RANDOM % 10));
env:
SANDBOX_ID: ${{ github.event.inputs.sandbox-id }}
- id: create-pipeline-fargate-profile
name: Attempt to create pipeline Fargate profile
uses: nick-invision/retry@v2
with:
timeout_seconds: 900
max_attempts: 30
retry_on: error
command: |
output=$(eksctl create fargateprofile --cluster biomage-staging --region ${{ secrets.AWS_REGION }} --name pipeline-${SANDBOX_ID} --labels type=pipeline --namespace pipeline-${SANDBOX_ID} 2>&1)
echo $output
echo $output | grep "created Fargate profile"
# Add jitter to break up correlated events.
on_retry_command: sleep $((20 + RANDOM % 10))
env:
SANDBOX_ID: ${{ github.event.inputs.sandbox-id }}
- id: deploy-template-rds
# if: ${{ github.ref == 'refs/heads/master' && github.event.inputs.with-rds == 'True' }}
if: ${{ github.event.inputs.with-rds == 'True' }}
name: Deploy CloudFormation stack for RDS
uses: aws-actions/aws-cloudformation-github-deploy@v1
with:
parameter-overrides: "Environment=staging,SandboxID=${{ github.event.inputs.sandbox-id }}"
name: ${{ steps.set-stack-name.outputs.rds-name }}
template: cf/rds.yaml
no-fail-on-empty-changeset: "1"
capabilities: "CAPABILITY_IAM,CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND"
- id: rds-secrets
if: ${{ github.event.inputs.with-rds == 'True' }}
uses: t-botz/aws-secrets-manager-read-action@v2
name: Outputs RDS secrets to get into the db
with:
secret-id: aurora-staging-${{ github.event.inputs.sandbox-id }}
mask-value: true
mask-json-values: true
keys-as-outputs: true
- id: setup-rds-roles
# if: ${{ github.ref == 'refs/heads/master' && github.event.inputs.with-rds == 'True' }}
if: ${{ github.event.inputs.with-rds == 'True' }}
name: Setup RDS roles
run: |-
INSTANCE_ID=$(aws ec2 describe-instances \
--filters 'Name=tag:Name,Values=rds-staging-ssm-agent' \
--output text \
--query 'Reservations[*].Instances[*].InstanceId')
if [ -z $INSTANCE_ID ]; then
echo "Can not connect to RDS agent: No instances found for staging"
exit 1
fi
CLUSTER_NAME=aurora-cluster-staging-${SANDBOX_ID}
RDSHOST=$(aws rds describe-db-cluster-endpoints \
--region $REGION \
--db-cluster-identifier $CLUSTER_NAME \
--filter Name=db-cluster-endpoint-type,Values='writer' \
--query 'DBClusterEndpoints[0].Endpoint' \
--output text)
if [ -z $RDSHOST ]; then
echo "Failed getting RDS host with name $CLUSTER_NAME"
exit 1
fi
ENSURE_PSQL_INSTALLED_COMMAND="sudo yum -y install postgresql"
aws ssm send-command --instance-ids "$INSTANCE_ID" \
--document-name AWS-RunShellScript \
--parameters "commands='$ENSURE_PSQL_INSTALLED_COMMAND'"
SETUP_ROLES_CMD="
PGPASSWORD=\'${AURORA_STAGING_PASSWORD}\' psql \
--host=${RDSHOST} \
--port=5432 \
--username=${AURORA_STAGING_USERNAME} \
--dbname=aurora_db <<EOF
CREATE ROLE api_role WITH LOGIN;
CREATE ROLE dev_role WITH LOGIN;
GRANT USAGE ON SCHEMA public TO api_role;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public to api_role;
GRANT dev_role TO ${AURORA_STAGING_USERNAME};
ALTER DEFAULT PRIVILEGES FOR USER dev_role IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO api_role;
ALTER DEFAULT PRIVILEGES FOR USER dev_role IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO api_role;
REVOKE dev_role FROM ${AURORA_STAGING_USERNAME};
GRANT rds_iam TO api_role;
GRANT rds_iam, ${AURORA_STAGING_USERNAME} TO dev_role;
EOF"
aws ssm send-command --instance-ids "$INSTANCE_ID" \
--document-name AWS-RunShellScript \
--parameters "commands='$SETUP_ROLES_CMD'"
env:
REGION: ${{ env.region }}
SANDBOX_ID: ${{ github.event.inputs.sandbox-id }}
AURORA_STAGING_USERNAME: ${{ steps.rds-secrets.outputs.username }}
AURORA_STAGING_PASSWORD: ${{ steps.rds-secrets.outputs.password }}
- id: deploy-template-sns
name: Deploy CloudFormation stack for SNS topic
uses: aws-actions/aws-cloudformation-github-deploy@v1
with:
parameter-overrides: "Environment=staging,SandboxID=${{ github.event.inputs.sandbox-id }}"
name: ${{ steps.set-stack-name.outputs.sns-name }}
template: cf/sns.yaml
no-fail-on-empty-changeset: "1"
capabilities: "CAPABILITY_IAM,CAPABILITY_NAMED_IAM"
- id: deploy-template-userpool-client
name: Deploy CloudFormation stack for Cognito userpool clients
uses: aws-actions/aws-cloudformation-github-deploy@v1
with:
parameter-overrides: "Environment=staging,SandboxID=${{ github.event.inputs.sandbox-id }}"
name: ${{ steps.set-stack-name.outputs.userpoolclient-name }}
template: cf/userpoolclient.yaml
no-fail-on-empty-changeset: "1"
capabilities: "CAPABILITY_IAM,CAPABILITY_NAMED_IAM"
- id: deploy-template-batch-job-definition
name: Deploy CloudFormation stack for Batch job definition
uses: aws-actions/aws-cloudformation-github-deploy@v1
with:
parameter-overrides: >-
Environment=staging,
SandboxID=${{ github.event.inputs.sandbox-id }},
PipelinePRNum=${{ github.event.inputs.pipeline-pr }},
ImageAccountId=${{ needs.load-config.outputs.image_account_id }},
ImageAccountRegion=${{ needs.load-config.outputs.image_account_region }}
name: ${{ steps.set-stack-name.outputs.batch-job-definition-name }}
template: cf/batch-job-definition.yaml
no-fail-on-empty-changeset: "1"
capabilities: "CAPABILITY_IAM,CAPABILITY_NAMED_IAM"
- id: create-manifest-file
name: Create manifest file to repository.
run: |-
echo "$MANIFEST" | base64 -d > $SANDBOX_ID.yaml
env:
MANIFEST: ${{ github.event.inputs.manifest }}
SANDBOX_ID: ${{ github.event.inputs.sandbox-id }}
- id: push-deployment-to-releases
name: Push staging deployment template to releases
uses: dmnemec/[email protected]
env:
API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }}
with:
source_file: ${{ github.event.inputs.sandbox-id }}.yaml
destination_repo: ${{ github.repository_owner }}/releases
destination_folder: staging
user_email: [email protected]
user_name: 'Biomage CI/CD'
- id: add-kubeconfig
name: Add k8s config to enable removal of Fargate profile on failure
if: ${{ failure() }}
run: |-
aws eks update-kubeconfig --name biomage-staging
- id: cleanup-pipeline-fargate-profile-if-failure
name: Remove Fargate profile for the pipelines
if: ${{ failure() }}
uses: nick-invision/retry@v2
with:
timeout_seconds: 900
max_attempts: 30
retry_on: error
command: |
output=$(eksctl delete fargateprofile --cluster biomage-staging --region ${{ secrets.AWS_REGION }} --name pipeline-${SANDBOX_ID} 2>&1)
echo $output
echo $output | egrep "deleted Fargate profile|No Fargate Profile found"
# Add jitter to break up correlated events.
on_retry_command: sleep $((20 + RANDOM % 10));
env:
SANDBOX_ID: ${{ github.event.inputs.sandbox-id }}
- id: cleanup-worker-fargate-profile-if-failure
name: Remove Fargate profile for the workers
if: ${{ failure() }}
uses: nick-invision/retry@v2
with:
timeout_seconds: 900
max_attempts: 30
retry_on: error
command: |
output=$(eksctl delete fargateprofile --cluster biomage-staging --region ${{ secrets.AWS_REGION }} --name worker-${SANDBOX_ID} 2>&1)
echo $output
echo $output | egrep "deleted Fargate profile|No Fargate Profile found"
# Add jitter to break up correlated events.
on_retry_command: sleep $((20 + RANDOM % 10));
env:
SANDBOX_ID: ${{ github.event.inputs.sandbox-id }}