Skip to content

Commit f8fd0af

Browse files
committed
Review apps: add Terraform in support of forms-runner review apps
This Terraform is cloned from the equivalent code in forms-admin, and adjusted for the needs of forms-runner. The code duplication is a choice we made, because these two sets of Terraform code are only similar, and not the same bar some parameter differences. Trying to share code between the two would cause more problems than it solves.
1 parent b2e6a73 commit f8fd0af

File tree

13 files changed

+625
-0
lines changed

13 files changed

+625
-0
lines changed

.github/workflows/terraform.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: "Terraform"
2+
on:
3+
pull_request:
4+
branches: [main]
5+
paths:
6+
- ".review_apps/**"
7+
merge_group:
8+
types: [checks_requested]
9+
env:
10+
TERRAFORM_VERSION: "1.11.0"
11+
jobs:
12+
terraform:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- uses: hashicorp/setup-terraform@v3
19+
with:
20+
terraform_version: ${{env.TERRAFORM_VERSION}}
21+
22+
- name: Check Terraform style
23+
id: tf_fmt
24+
working-directory: ".review_apps/"
25+
run: |
26+
terraform fmt -write=false -diff=true -list=true -recursive -check
27+
28+
- name: Lint Terraform
29+
run: |
30+
pip install -r .review_apps/requirements.txt
31+
checkov -d .review_apps/ --framework terraform --quiet
32+
33+
- name: Validate Terraform syntax
34+
working-directory: ".review_apps/"
35+
run : |
36+
terraform init -backend=false || exit
37+
terraform validate

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,6 @@ config/settings/*.local.yml
5454
config/environments/*.local.yml
5555

5656
.DS_Store
57+
58+
# Terraform
59+
.terraform/

.review_apps/.terraform-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.11.0

.review_apps/.terraform.lock.hcl

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.review_apps/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Review apps
2+
3+
The Terraform code in this directory is used to deploy a review copy of `forms-admin`.
4+
5+
It constructs a minimal, ephemeral version of a GOV.UK Forms environment in AWS ECS that can be used for reviews, then freely destroyed. This includes:
6+
7+
* a copy of `forms-admin` at the commit in question
8+
* a copy of the version of `forms-api` currently in production
9+
* a local PostgreSQL database with seed data for both `forms-api` and `forms-admin`
10+
11+
Review apps rely on a set of underlying infrastructure managed and deployed in `forms-deploy`. The Terraform will require you to be targeting the `integration` AWS account (where the `review` environment lives), and you should not override this.
12+
13+
### State files
14+
Each review app uses its own Terraform state file, stored in an S3 bucket. The bucket itself is created and managed by `forms-deploy` and its name is safely assumed.
15+
16+
### `forms-admin` container image
17+
The `forms-admin` container image to deploy is supplied under the `forms_admin_container_image` variable. Terraform does not build the container. It is assumed to be built and stored ahead of time.
18+
19+

.review_apps/app_autoscaling.tf

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
resource "aws_appautoscaling_target" "review_app" {
2+
service_namespace = "ecs"
3+
resource_id = "service/${data.terraform_remote_state.review.outputs.ecs_cluster_id}/${aws_ecs_service.app.name}"
4+
scalable_dimension = "ecs:service:DesiredCount"
5+
6+
max_capacity = 1
7+
min_capacity = 1
8+
}
9+
10+
resource "aws_appautoscaling_scheduled_action" "shutdown_at_night" {
11+
name = "forms-runner-pr-${var.pull_request_number}-shutdown-at-night"
12+
13+
service_namespace = aws_appautoscaling_target.review_app.service_namespace
14+
resource_id = aws_appautoscaling_target.review_app.resource_id
15+
scalable_dimension = aws_appautoscaling_target.review_app.scalable_dimension
16+
17+
schedule = "cron(0 18 * * ? *)" # daily at 1800
18+
19+
scalable_target_action {
20+
min_capacity = 0
21+
max_capacity = 0
22+
}
23+
}
24+
25+
resource "aws_appautoscaling_scheduled_action" "startup_weekday_mornings" {
26+
name = "forms-runner-pr-${var.pull_request_number}-startup-weekday-mornings"
27+
28+
service_namespace = aws_appautoscaling_target.review_app.service_namespace
29+
resource_id = aws_appautoscaling_target.review_app.resource_id
30+
scalable_dimension = aws_appautoscaling_target.review_app.scalable_dimension
31+
32+
schedule = "cron(0 8 ? * MON-FRI *)" # Monday-Friday at 0800
33+
34+
scalable_target_action {
35+
min_capacity = 1
36+
max_capacity = 1
37+
}
38+
}

.review_apps/dependencies.tf

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
##
2+
# Terraform remote state data resources are
3+
# used to read the content of a Terraform state
4+
# file.
5+
#
6+
# This is common pattern in the `forms-deploy`
7+
# codebase, and is used to share information
8+
# between different Terraform roots without
9+
# having to do any external wiring of outputs
10+
# to inputs.
11+
#
12+
# In this instance, we will be sharing things
13+
# like the subnet and security groups ids that
14+
# are necessary for deploying to AWS ECS.
15+
##
16+
data "terraform_remote_state" "review" {
17+
backend = "s3"
18+
19+
config = {
20+
key = "review.tfstate"
21+
bucket = "gds-forms-integration-tfstate"
22+
region = "eu-west-2"
23+
24+
use_lockfile = true
25+
}
26+
}

.review_apps/ecs_service.tf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
resource "aws_ecs_service" "app" {
2+
#checkov:skip=CKV_AWS_332:We don't want to target "LATEST" and get a surprise when a new version is released.
3+
name = "forms-runner-pr-${var.pull_request_number}"
4+
5+
cluster = data.terraform_remote_state.review.outputs.ecs_cluster_id
6+
task_definition = aws_ecs_task_definition.task.arn
7+
8+
desired_count = 1
9+
deployment_maximum_percent = "200"
10+
deployment_minimum_healthy_percent = "100"
11+
force_new_deployment = true
12+
13+
14+
launch_type = "FARGATE"
15+
platform_version = "1.4.0"
16+
17+
network_configuration {
18+
subnets = data.terraform_remote_state.review.outputs.private_subnet_ids
19+
security_groups = [data.terraform_remote_state.review.outputs.review_apps_security_group_id]
20+
assign_public_ip = false
21+
}
22+
23+
depends_on = [aws_ecs_task_definition.task]
24+
}

0 commit comments

Comments
 (0)