Skip to content

Commit 945d320

Browse files
authored
Noor1027/bb2 4616 refactor ci pipelines (#1543)
* workflow update with release tag * Update build-push-images.yml * Update build-push-images.yml * Update deploy-api-fargate.yml * Update base_ec2.py * Update base_ec2.py * fix: add SES email support for Fargate * Update test.sopsw.yaml * updating SG groups * Update iam.tf * workflow update with release tag * Update build-push-images.yml * Update build-push-images.yml * Update deploy-api-fargate.yml * Update base_ec2.py * Update base_ec2.py * fix: add SES email support for Fargate * Update test.sopsw.yaml * updating SG groups * Update iam.tf * Configure Fargate deployment endpoints and CI workflows * adding merge conflct * updated container name * Update deploy-api-fargate.yml * Update security_groups.tf * Trigger new docker build to bypass ECR immutable tag
1 parent e7959fa commit 945d320

18 files changed

Lines changed: 492 additions & 104 deletions

File tree

.github/actions/setup-tofu/action.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,20 @@ runs:
7272
echo "yq $(yq --version) already installed"
7373
fi
7474
75+
- name: Resolve role environment
76+
id: role-env
77+
shell: bash
78+
run: |
79+
# One role per account: sandbox reuses prod's role
80+
ENV="${{ inputs.environment }}"
81+
if [ "$ENV" = "sandbox" ]; then
82+
echo "env=prod" >> "$GITHUB_OUTPUT"
83+
else
84+
echo "env=$ENV" >> "$GITHUB_OUTPUT"
85+
fi
86+
7587
- name: Configure AWS Credentials
7688
uses: aws-actions/configure-aws-credentials@v4
7789
with:
78-
role-to-assume: arn:aws:iam::${{ steps.account.outputs.account }}:role/delegatedadmin/developer/bb-${{ inputs.environment }}-github-actions
90+
role-to-assume: arn:aws:iam::${{ steps.account.outputs.account }}:role/delegatedadmin/developer/bb-${{ steps.role-env.outputs.env }}-github-actions
7991
aws-region: us-east-1
Lines changed: 82 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,121 @@
1-
# Build and Deploy - Test
1+
# Build and Push Container Image
22

3-
name: Build Image and Publish to ECR
3+
name: Build and Push Image
44

55
on:
66
workflow_dispatch:
77
inputs:
88
environment:
9-
description: 'Environment to deploy to'
9+
description: 'Environment to build for'
1010
required: true
1111
default: 'test'
1212
type: choice
1313
options:
1414
- test
15-
- impl
1615
- prod
17-
version:
18-
description: 'Version to deploy'
19-
required: true
20-
default: 'none'
16+
release_tag:
17+
description: 'Release tag to build (e.g. r33) — uses master HEAD if empty'
18+
required: false
19+
type: string
20+
workflow_call:
21+
inputs:
22+
environment:
23+
required: false
24+
type: string
25+
default: 'test'
26+
release_tag:
27+
required: false
2128
type: string
2229

2330
env:
2431
AWS_REGION: us-east-1
2532

2633
permissions:
27-
id-token: write # Required for requ esting the AWS IAM OIDC JWT
28-
contents: write # Required for actions/checkout
29-
actions: write # Required for GHA cache
34+
id-token: write # Required for requesting the AWS IAM OIDC JWT
35+
contents: read # Required for actions/checkout
36+
actions: write # Required for GHA cache
3037

3138
jobs:
3239
build:
3340
# This runs on CodeBuild, not a public GitHub Action Runner.
34-
# TODO - Optimize CodeBuile usage, use public runners when appropriate
41+
# sandbox uses prod CodeBuild runner (same account)
3542
runs-on:
36-
- codebuild-bb-${{ github.event.inputs.environment || 'test' }}-web-server-${{ github.run_id }}-${{ github.run_attempt }}
43+
- codebuild-bb-${{ (inputs.environment || 'test') == 'test' && 'test' || 'prod' }}-web-server-${{ github.run_id }}-${{ github.run_attempt }}
44+
45+
outputs:
46+
image_tag: ${{ steps.resolve-tag.outputs.image_tag }}
3747

3848
steps:
49+
- name: Resolve image tag
50+
id: resolve-tag
51+
run: |
52+
if [[ -n "${{ inputs.release_tag }}" ]]; then
53+
echo "image_tag=${{ inputs.release_tag }}" >> "$GITHUB_OUTPUT"
54+
else
55+
echo "image_tag=${{ github.sha }}" >> "$GITHUB_OUTPUT"
56+
fi
57+
3958
- name: Checkout
4059
uses: actions/checkout@v4
60+
with:
61+
ref: ${{ inputs.release_tag || github.ref_name }}
4162

42-
- name: Configure AWS credentials
43-
id: aws-creds
44-
uses: aws-actions/configure-aws-credentials@v4
63+
- name: Setup AWS credentials (Test)
64+
uses: ./.github/actions/setup-tofu
4565
with:
46-
role-to-assume: ${{ secrets.AWS_ROLE_ARN_TEST }}
47-
aws-region: ${{ env.AWS_REGION }}
48-
mask-aws-account-id: true
66+
environment: test
67+
non-prod-account: ${{ secrets.NON_PROD_ACCOUNT }}
68+
prod-account: ${{ secrets.PROD_ACCOUNT }}
4969

50-
- name: Mask additional sensitive values
70+
- name: Login to Amazon ECR (Test)
71+
id: login-ecr-test
72+
uses: aws-actions/amazon-ecr-login@v2
73+
with:
74+
mask-password: true
75+
76+
- name: Mask ECR registry (Test)
5177
run: |
52-
# Mask the role ARN
53-
echo "::add-mask::${{ secrets.AWS_ROLE_ARN_TEST }}"
54-
# echo "::add-mask::${{ secrets.AWS_ROLE_ARN_IMPL }}"
55-
# echo "::add-mask::${{ secrets.AWS_ROLE_ARN_PROD }}"
56-
57-
# Get and mask account ID
58-
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
59-
echo "::add-mask::$ACCOUNT_ID"
60-
echo "account_id=$ACCOUNT_ID" >> $GITHUB_OUTPUT
61-
62-
- name: Login to Amazon ECR
63-
id: login-ecr
78+
echo "::add-mask::${{ steps.login-ecr-test.outputs.registry }}"
79+
80+
- name: Check for Prod Configuration
81+
id: check_prod
82+
env:
83+
PROD_ACCOUNT: ${{ secrets.PROD_ACCOUNT }}
84+
run: |
85+
if [[ -n "$PROD_ACCOUNT" ]]; then
86+
echo "has_prod=true" >> "$GITHUB_OUTPUT"
87+
else
88+
echo "has_prod=false" >> "$GITHUB_OUTPUT"
89+
fi
90+
91+
- name: Setup AWS credentials (Prod)
92+
if: steps.check_prod.outputs.has_prod == 'true'
93+
uses: ./.github/actions/setup-tofu
94+
with:
95+
environment: prod
96+
non-prod-account: ${{ secrets.NON_PROD_ACCOUNT }}
97+
prod-account: ${{ secrets.PROD_ACCOUNT }}
98+
99+
- name: Login to Amazon ECR (Prod)
100+
id: login-ecr-prod
101+
if: steps.check_prod.outputs.has_prod == 'true'
64102
uses: aws-actions/amazon-ecr-login@v2
65103
with:
66104
mask-password: true
67105

68-
- name: Mask ECR registry
106+
- name: Mask ECR registry (Prod)
107+
if: steps.check_prod.outputs.has_prod == 'true'
69108
run: |
70-
echo "::add-mask::${{ steps.login-ecr.outputs.registry }}"
109+
echo "::add-mask::${{ steps.login-ecr-prod.outputs.registry }}"
71110
72-
- name: Untag previous "latest"
111+
- name: Prepare Image Tags
112+
id: prep_tags
73113
run: |
74-
aws ecr batch-delete-image --repository-name bb-${{ github.event.inputs.environment || 'test' }}-api --image-ids imageTag="latest"
114+
TAGS="${{ steps.login-ecr-test.outputs.registry }}/bb-test-api:${{ steps.resolve-tag.outputs.image_tag }}"
115+
if [[ "${{ steps.check_prod.outputs.has_prod }}" == "true" ]]; then
116+
TAGS="${TAGS},${{ steps.login-ecr-prod.outputs.registry }}/bb-prod-api:${{ steps.resolve-tag.outputs.image_tag }}"
117+
fi
118+
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
75119
76120
- name: Setup Buildx
77121
uses: docker/setup-buildx-action@v3
@@ -84,10 +128,9 @@ jobs:
84128
platforms: linux/arm64
85129
push: true
86130
provenance: false
87-
tags: |
88-
${{ steps.login-ecr.outputs.registry }}/bb-${{ github.event.inputs.environment || 'test' }}-api:${{ github.sha }}
89-
${{ steps.login-ecr.outputs.registry }}/bb-${{ github.event.inputs.environment || 'test' }}-api:latest
131+
tags: ${{ steps.prep_tags.outputs.tags }}
90132
build-args: |
91133
BUILD_TARGET=production
134+
RELEASE_TAG=${{ steps.resolve-tag.outputs.image_tag }}
92135
cache-from: type=gha
93136
cache-to: type=gha,mode=max
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
name: Deploy to Fargate
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
environment:
7+
description: 'Environment to deploy to'
8+
required: true
9+
type: choice
10+
options:
11+
- test
12+
- sandbox
13+
- prod
14+
image_tag:
15+
description: 'ECR image tag to deploy (e.g. r33)'
16+
required: true
17+
type: string
18+
19+
env:
20+
AWS_REGION: us-east-1
21+
22+
permissions:
23+
id-token: write
24+
contents: read
25+
26+
jobs:
27+
deploy:
28+
name: Deploy ${{ inputs.image_tag || github.sha }} to ${{ inputs.environment || 'test' }}
29+
# sandbox uses prod CodeBuild runner (same account)
30+
runs-on:
31+
- codebuild-bb-${{ (inputs.environment || 'test') == 'test' && 'test' || 'prod' }}-web-server-${{ github.run_id }}-${{ github.run_attempt }}
32+
environment: ${{ inputs.environment || 'test' }}
33+
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- name: Setup AWS credentials
38+
uses: ./.github/actions/setup-tofu
39+
with:
40+
environment: ${{ inputs.environment || 'test' }}
41+
non-prod-account: ${{ secrets.NON_PROD_ACCOUNT }}
42+
prod-account: ${{ secrets.PROD_ACCOUNT }}
43+
44+
- name: Login to Amazon ECR
45+
id: login-ecr
46+
uses: aws-actions/amazon-ecr-login@v2
47+
with:
48+
mask-password: true
49+
50+
- name: Mask ECR registry
51+
run: |
52+
echo "::add-mask::${{ steps.login-ecr.outputs.registry }}"
53+
54+
- name: Verify image exists in ECR
55+
id: verify-image
56+
run: |
57+
ENV="${{ inputs.environment || 'test' }}"
58+
# sandbox and prod share the same ECR repo (bb-prod-api)
59+
BUCKET_ENV="${ENV}"
60+
if [[ "$ENV" == "sandbox" ]]; then
61+
BUCKET_ENV="prod"
62+
fi
63+
64+
REPO_NAME="bb-${BUCKET_ENV}-api"
65+
IMAGE_TAG="${{ inputs.image_tag || github.sha }}"
66+
67+
echo "Verifying ${REPO_NAME}:${IMAGE_TAG} exists in ECR..."
68+
if ! aws ecr describe-images --repository-name "$REPO_NAME" --image-ids imageTag="$IMAGE_TAG" > /dev/null 2>&1; then
69+
echo "::error::Image ${REPO_NAME}:${IMAGE_TAG} not found in ECR. Build it first."
70+
exit 1
71+
fi
72+
73+
REGISTRY="${{ steps.login-ecr.outputs.registry }}"
74+
echo "image=${REGISTRY}/${REPO_NAME}:${IMAGE_TAG}" >> "$GITHUB_OUTPUT"
75+
echo "Image verified: ${REPO_NAME}:${IMAGE_TAG}"
76+
77+
- name: Get current task definition
78+
id: current-task
79+
run: |
80+
ENV="${{ inputs.environment || 'test' }}"
81+
FAMILY="bb-${ENV}-api-family"
82+
83+
echo "Fetching current task definition for ${FAMILY}..."
84+
TASK_DEF=$(aws ecs describe-task-definition --task-definition "$FAMILY" --query 'taskDefinition')
85+
86+
# Update the image in the container definition
87+
UPDATED=$(echo "$TASK_DEF" | jq \
88+
--arg IMAGE "${{ steps.verify-image.outputs.image }}" \
89+
'.containerDefinitions[0].image = $IMAGE')
90+
91+
# Strip fields that cannot be included in register-task-definition
92+
CLEANED=$(echo "$UPDATED" | jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)')
93+
94+
echo "$CLEANED" > /tmp/task-definition.json
95+
echo "Updated image to: ${{ steps.verify-image.outputs.image }}"
96+
97+
- name: Register new task definition
98+
id: register-task
99+
run: |
100+
NEW_TASK_DEF=$(aws ecs register-task-definition \
101+
--cli-input-json file:///tmp/task-definition.json \
102+
--query 'taskDefinition.taskDefinitionArn' \
103+
--output text)
104+
105+
echo "task_definition_arn=$NEW_TASK_DEF" >> "$GITHUB_OUTPUT"
106+
echo "Registered: $NEW_TASK_DEF"
107+
108+
- name: Update ECS service
109+
run: |
110+
ENV="${{ inputs.environment || 'test' }}"
111+
CLUSTER="bb-${ENV}-cluster"
112+
SERVICE="bb-${ENV}-api-service"
113+
114+
echo "Updating ${SERVICE} on ${CLUSTER}..."
115+
aws ecs update-service \
116+
--cluster "$CLUSTER" \
117+
--service "$SERVICE" \
118+
--task-definition "${{ steps.register-task.outputs.task_definition_arn }}" \
119+
--force-new-deployment \
120+
--query 'service.serviceName' \
121+
--output text
122+
123+
- name: Wait for deployment to stabilize
124+
run: |
125+
ENV="${{ inputs.environment || 'test' }}"
126+
CLUSTER="bb-${ENV}-cluster"
127+
SERVICE="bb-${ENV}-api-service"
128+
129+
echo "Waiting for ${SERVICE} to stabilize (timeout: 10 minutes)..."
130+
aws ecs wait services-stable \
131+
--cluster "$CLUSTER" \
132+
--services "$SERVICE" || {
133+
echo "::warning::Service did not stabilize within timeout. Check ECS console."
134+
exit 1
135+
}
136+
137+
echo "Deployment complete and stable."

0 commit comments

Comments
 (0)