Skip to content

Commit aa8be83

Browse files
authored
Merge pull request #4787 from nhsuk/next
Version 4.5.0
2 parents 1060d03 + 9d212da commit aa8be83

108 files changed

Lines changed: 2173 additions & 1234 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-and-push-image.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
name: Build and push image
2+
run-name: Build and push image for ${{ inputs.git-sha || github.sha }}
23

34
on:
45
workflow_dispatch:
56
inputs:
6-
git-sha:
7+
git_sha:
78
description: The FULL git commit sha to build the image from (optional).
89
type: string
910
workflow_call:
1011
inputs:
11-
git-sha:
12+
git_sha:
1213
description: The git commit sha to build the image from.
1314
type: string
1415

1516
env:
1617
PUSH_IMAGE_TO_PRODUCTION: ${{ github.ref_name == 'main' }}
17-
git_ref: ${{ inputs.git-sha || github.sha }}
18+
git_ref: ${{ inputs.git_sha || github.sha }}
1819

1920
concurrency:
20-
group: build-and-push-image-${{ inputs.git-sha || github.sha }}
21+
group: build-and-push-image-${{ inputs.git_sha || github.sha }}
2122

2223
permissions: {}
2324

Lines changed: 105 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
name: Data replication pipeline
2-
run-name: ${{ inputs.deployment_type }} for data replication resources for ${{ inputs.environment }}
1+
name: Deploy data replication
2+
run-name: Deploy data replication to ${{ inputs.environment }}
33

44
on:
55
workflow_dispatch:
@@ -15,198 +15,127 @@ on:
1515
- qa
1616
- sandbox-alpha
1717
- sandbox-beta
18-
deployment_type:
19-
description: Deployment type
20-
required: true
21-
type: choice
22-
options:
23-
- Deployment with DB recreation
24-
- Application only deployment
25-
image_tag:
26-
description: Docker image tag to deploy
27-
required: false
28-
type: string
29-
db_snapshot_arn:
30-
description: ARN of the DB snapshot to use (optional)
31-
required: false
18+
git_ref_to_deploy:
19+
description:
20+
| # Use blank unicode character (U+2800) to force line-break
21+
Use code from: ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
22+
(Git ref to deploy, for example, a tag, branch name or commit SHA. Will use workflow ref if not provided.)
3223
type: string
33-
egress_cidr:
34-
description: CIDR blocks to allow egress traffic.
35-
type: string
36-
required: true
37-
default: "[]"
38-
take_db_snapshot:
39-
description: Take a new DB snapshot before creating the environment
40-
type: boolean
41-
default: false
24+
25+
permissions: {}
4226

4327
env:
4428
environment: ${{ inputs.environment }}
4529
deployment_type: ${{ inputs.deployment_type }}
4630
db_snapshot_arn: ${{ inputs.db_snapshot_arn }}
4731
egress_cidr: ${{ inputs.egress_cidr }}
4832
take_db_snapshot: ${{ inputs.take_db_snapshot }}
33+
git_ref: ${{ inputs.git_ref_to_deploy || github.sha }}
4934
aws_role: ${{ inputs.environment == 'production'
5035
&& 'arn:aws:iam::820242920762:role/GithubDeployDataReplicationInfrastructure'
5136
|| 'arn:aws:iam::393416225559:role/GithubDeployDataReplicationInfrastructure' }}
52-
db_snapshot_role: ${{ inputs.environment == 'production'
53-
&& 'arn:aws:iam::820242920762:role/DatabaseSnapshotRole'
54-
|| 'arn:aws:iam::393416225559:role/DatabaseSnapshotRole' }}
55-
56-
defaults:
57-
run:
58-
working-directory: terraform/data_replication
37+
aws_account_id: ${{ inputs.environment == 'production' && '820242920762' || '393416225559' }}
5938

6039
concurrency:
6140
group: deploy-data-replica-${{ inputs.environment }}
6241

6342
jobs:
64-
prepare-db-replica:
65-
if: ${{ inputs.deployment_type == 'Deployment with DB recreation' }}
66-
name: Prepare data replica
43+
validate-inputs:
6744
runs-on: ubuntu-latest
68-
permissions:
69-
id-token: write
45+
permissions: {}
7046
steps:
71-
- name: Checkout code
72-
uses: actions/checkout@v5
73-
- name: Assume DB Snapshot role
74-
if: inputs.take_db_snapshot
75-
uses: aws-actions/configure-aws-credentials@v5
76-
with:
77-
role-to-assume: ${{ env.db_snapshot_role }}
78-
aws-region: eu-west-2
79-
- name: Take DB snapshot
80-
if: inputs.take_db_snapshot
81-
run: |
82-
set -e
83-
snapshot_identifier=snapshot-for-data-replication-$(date +"%Y-%m-%d-%H-%M-%S")
84-
aws rds create-db-cluster-snapshot --db-cluster-identifier mavis-$environment --db-cluster-snapshot-identifier $snapshot_identifier
85-
echo "Waiting for snapshot to be available. This can take a while."
86-
aws rds wait db-cluster-snapshot-available --db-cluster-snapshot-identifier $snapshot_identifier
87-
echo "New snapshot is now available"
88-
- name: Configure AWS Credentials
89-
uses: aws-actions/configure-aws-credentials@v5
90-
with:
91-
role-to-assume: ${{ env.aws_role }}
92-
aws-region: eu-west-2
93-
- name: Get latest snapshot
94-
id: get-latest-snapshot
47+
- name: Validate inputs
9548
run: |
96-
set -e
97-
if [ -z "$db_snapshot_arn" ]; then
98-
echo "No snapshot ARN provided, fetching the latest snapshot"
99-
SNAPSHOT_ARN=$(aws rds describe-db-cluster-snapshots \
100-
--query "DBClusterSnapshots[?DBClusterIdentifier=='mavis-$environment'].[DBClusterSnapshotArn, SnapshotCreateTime]" \
101-
--output text | sort -k2 -r | head -n 1 | cut -f1)
102-
103-
if [ -z "$SNAPSHOT_ARN" ]; then
104-
echo "No snapshots found for mavis-$environment"
105-
exit 1
106-
fi
107-
else
108-
echo "Using provided snapshot ARN: $db_snapshot_arn"
109-
SNAPSHOT_ARN="$db_snapshot_arn"
49+
if [[ "$environment" == "preview" || "$environment" == "production" ]]; then
50+
if [[ -z "$git_ref_to_deploy" ]]; then
51+
echo "Error: git_ref_to_deploy is required for preview and production environments."
52+
exit 1
53+
fi
11054
fi
111-
echo "Using snapshot ARN: $SNAPSHOT_ARN"
112-
echo "SNAPSHOT_ARN=$SNAPSHOT_ARN" >> $GITHUB_OUTPUT
113-
- name: Install terraform
114-
uses: hashicorp/setup-terraform@v3
115-
with:
116-
terraform_version: 1.13.3
117-
outputs:
118-
SNAPSHOT_ARN: ${{ steps.get-latest-snapshot.outputs.SNAPSHOT_ARN }}
11955
120-
prepare-webapp:
121-
name: Prepare webapp
56+
determine-git-sha:
12257
runs-on: ubuntu-latest
123-
permissions:
124-
id-token: write
58+
permissions: {}
59+
needs: validate-inputs
60+
outputs:
61+
git-sha: ${{ steps.get-git-sha.outputs.git-sha }}
12562
steps:
12663
- name: Checkout code
12764
uses: actions/checkout@v5
128-
- name: Configure AWS Credentials
129-
uses: aws-actions/configure-aws-credentials@v5
13065
with:
131-
role-to-assume: ${{ env.aws_role }}
132-
aws-region: eu-west-2
133-
- name: ECR login
134-
id: login-ecr
135-
uses: aws-actions/amazon-ecr-login@v2
136-
- name: Get docker image digest
137-
id: get-docker-image-digest
138-
env:
139-
IMAGE_TAG: ${{ inputs.image_tag || github.sha }}
140-
run: |
141-
set -e
142-
DOCKER_IMAGE="${{ steps.login-ecr.outputs.registry }}/mavis/webapp:$IMAGE_TAG"
143-
docker pull "$DOCKER_IMAGE"
144-
DOCKER_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$DOCKER_IMAGE")
145-
DIGEST="${DOCKER_DIGEST#*@}"
146-
echo "DIGEST=$DIGEST" >> $GITHUB_OUTPUT
147-
outputs:
148-
DOCKER_DIGEST: ${{ steps.get-docker-image-digest.outputs.DIGEST }}
66+
ref: ${{ env.git_ref }}
67+
- name: Get git sha
68+
id: get-git-sha
69+
run: echo "git-sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
14970

150-
plan:
151-
name: Terraform plan
71+
build-and-push-image:
72+
permissions:
73+
id-token: write
74+
needs: determine-git-sha
75+
uses: ./.github/workflows/build-and-push-image.yml
76+
with:
77+
git_sha: ${{ needs.determine-git-sha.outputs.git-sha }}
78+
79+
prepare-deployment:
80+
name: Prepare deployment
15281
runs-on: ubuntu-latest
153-
needs:
154-
- prepare-db-replica
155-
- prepare-webapp
156-
if: ${{ !cancelled() &&
157-
(needs.prepare-db-replica.result == 'success' || needs.prepare-db-replica.result == 'skipped') &&
158-
needs.prepare-webapp.result == 'success' }}
159-
env:
160-
SNAPSHOT_ARN: ${{ needs.prepare-db-replica.outputs.SNAPSHOT_ARN }}
161-
DB_SECRET_ARN: ${{ needs.prepare-db-replica.outputs.DB_SECRET_ARN || 'arn:aws:secretsmanager:eu-west-2:000000000000:secret:placeholder' }}
162-
DOCKER_DIGEST: ${{ needs.prepare-webapp.outputs.DOCKER_DIGEST }}
163-
REPLACE_DB_CLUSTER: ${{ inputs.deployment_type == 'Deployment with DB recreation' }}
82+
needs: build-and-push-image
16483
permissions:
16584
id-token: write
16685
steps:
16786
- name: Checkout code
16887
uses: actions/checkout@v5
88+
with:
89+
ref: ${{ env.git_ref }}
16990
- name: Configure AWS Credentials
17091
uses: aws-actions/configure-aws-credentials@v5
17192
with:
17293
role-to-assume: ${{ env.aws_role }}
17394
aws-region: eu-west-2
174-
- name: Install terraform
175-
uses: hashicorp/setup-terraform@v3
176-
with:
177-
terraform_version: 1.13.3
178-
- name: Get db secret arn
179-
id: get-db-secret-arn
180-
working-directory: terraform/app
95+
- name: Get image digest
96+
id: get-image-digest
18197
run: |
182-
terraform init -backend-config="env/$environment-backend.hcl" -upgrade
183-
DB_SECRET_ARN=$(terraform output --raw db_secret_arn)
184-
echo "DB_SECRET_ARN=$DB_SECRET_ARN" >> $GITHUB_OUTPUT
185-
- name: Terraform Plan
186-
id: plan
98+
digest=$(aws ecr describe-images \
99+
--repository-name mavis/webapp \
100+
--image-ids imageTag=$git_ref \
101+
--query 'imageDetails[0].imageDigest' \
102+
--output text)
103+
echo "digest=$digest" >> $GITHUB_OUTPUT
104+
- name: Parse environment variables
105+
id: parse-environment-variables
106+
env:
107+
MAVIS__PDS__RATE_LIMIT_PER_SECOND: ${{ inputs.environment == 'production' && 50 || 5 }}
187108
run: |
188-
set -eo pipefail
189-
terraform init -backend-config="env/$environment-backend.hcl" -upgrade
190-
191-
PLAN_ARGS=(
192-
"plan"
193-
"-var=image_digest=$DOCKER_DIGEST"
194-
"-var=db_secret_arn=${{ steps.get-db-secret-arn.outputs.DB_SECRET_ARN }}"
195-
"-var=imported_snapshot=$SNAPSHOT_ARN"
196-
"-var-file=env/$environment.tfvars"
197-
"-var=allowed_egress_cidr_blocks=$egress_cidr"
198-
"-out=${{ runner.temp }}/tfplan"
199-
)
200-
201-
if [ "$REPLACE_DB_CLUSTER" = "true" ]; then
202-
PLAN_ARGS+=("-replace" "aws_rds_cluster.cluster")
203-
fi
204-
terraform "${PLAN_ARGS[@]}" | tee ${{ runner.temp }}/tf_stdout
205-
- name: Upload artifact
109+
{
110+
echo 'parsed_env_vars<<EOF'
111+
echo "MAVIS__SPLUNK__ENABLED=false"
112+
echo "MAVIS__CIS2__ENABLED=false"
113+
echo "MAVIS__PDS__ENQUEUE_BULK_UPDATES=false"
114+
echo "MAVIS__PDS__RATE_LIMIT_PER_SECOND=$MAVIS__PDS__RATE_LIMIT_PER_SECOND"
115+
echo 'EOF'
116+
} >> "$GITHUB_OUTPUT"
117+
- name: Populate web task definition
118+
id: create-task-definition
119+
uses: aws-actions/amazon-ecs-render-task-definition@v1
120+
with:
121+
task-definition-family: "mavis-data-replication-task-definition-${{ inputs.environment }}-template"
122+
container-name: "application"
123+
image: "${{ env.aws_account_id }}.dkr.ecr.eu-west-2.amazonaws.com/mavis/webapp@${{ steps.get-image-digest.outputs.digest }}"
124+
environment-variables: ${{ steps.parse-environment-variables.outputs.parsed_env_vars }}
125+
- name: Rename task definition file
126+
run: mv ${{ steps.create-task-definition.outputs.task-definition }} ${{ runner.temp }}/data-replication-task-definition.json
127+
- name: Upload artifact for data-replication task definition
206128
uses: actions/upload-artifact@v4
207129
with:
208-
name: tfplan_infrastructure-${{ inputs.environment }}
209-
path: ${{ runner.temp }}/tfplan
130+
name: ${{ inputs.environment }}-data-replication-task-definition
131+
path: ${{ runner.temp }}/data-replication-task-definition.json
132+
133+
notify-approval-required:
134+
name: Notify on approval required
135+
runs-on: ubuntu-latest
136+
needs: prepare-deployment
137+
if: ${{ inputs.environment == 'production' }}
138+
steps:
210139
- name: Notify pending approval
211140
if: inputs.environment == 'production'
212141
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a
@@ -227,40 +156,41 @@ jobs:
227156
- type: "mrkdwn"
228157
text: "*Triggered by:*\n${{ github.actor }}"
229158
230-
apply:
231-
name: Terraform apply
159+
approve-deployments:
160+
name: Wait for approval if required
232161
runs-on: ubuntu-latest
233-
needs: plan
234-
if: ${{ !cancelled() && needs.plan.result == 'success' }}
162+
needs: prepare-deployment
235163
environment: ${{ inputs.environment }}
164+
steps:
165+
- run: echo "Proceeding with deployment to $environment environment"
166+
167+
deploy-data-replication:
168+
name: Deploy data-replication service
169+
runs-on: ubuntu-latest
170+
needs: [prepare-deployment, approve-deployments]
236171
permissions:
237172
id-token: write
238173
steps:
239-
- name: Checkout code
240-
uses: actions/checkout@v5
241174
- name: Configure AWS Credentials
242175
uses: aws-actions/configure-aws-credentials@v5
243176
with:
244177
role-to-assume: ${{ env.aws_role }}
245178
aws-region: eu-west-2
246-
- name: Download artifact
179+
- name: Download data-replication task definition artifact
247180
uses: actions/download-artifact@v5
248181
with:
249-
name: tfplan_infrastructure-${{ inputs.environment }}
250182
path: ${{ runner.temp }}
251-
- name: Install terraform
252-
uses: hashicorp/setup-terraform@v3
253-
with:
254-
terraform_version: 1.13.3
255-
- name: Apply the changes
256-
run: |
257-
set -e
258-
terraform init -backend-config="env/$environment-backend.hcl" -upgrade
259-
terraform apply ${{ runner.temp }}/tfplan
260-
- name: Deploy db-access-service
183+
name: ${{ inputs.environment }}-data-replication-task-definition
184+
- name: Change family of task definition
261185
run: |
262-
task_definition_arn=$(terraform output -raw task_definition_arn)
263-
aws ecs update-service \
264-
--cluster "mavis-$environment-data-replication" \
265-
--service "mavis-$environment-data-replication" \
266-
--task-definition $task_definition_arn
186+
file_path="${{ runner.temp }}/data-replication-task-definition.json"
187+
family_name="mavis-data-replication-task-definition-$environment"
188+
echo "$(jq --arg f "$family_name" '.family = $f' "$file_path")" > "$file_path"
189+
- name: Deploy data-replication service
190+
uses: aws-actions/amazon-ecs-deploy-task-definition@v2
191+
with:
192+
task-definition: ${{ runner.temp }}/data-replication-task-definition.json
193+
cluster: mavis-${{ inputs.environment }}-data-replication
194+
service: mavis-${{ inputs.environment }}-data-replication
195+
force-new-deployment: true
196+
wait-for-service-stability: true

0 commit comments

Comments
 (0)