Skip to content

Commit 7aac3f0

Browse files
Merge pull request #167 from cabinetoffice/holding-page
Holding page
2 parents 2742c2a + 6649ac2 commit 7aac3f0

8 files changed

Lines changed: 8742 additions & 0 deletions

File tree

aws/README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# CloudFront Holding Page Runbook
2+
3+
This folder contains helper scripts used to switch Find a Grant between live origins and a static S3 holding page, and to update the holding page content.
4+
5+
## Script locations
6+
7+
- Runtime scripts are in `gap-find-web/aws/s3/`
8+
9+
## First stage: download scripts in CloudShell
10+
11+
Start by copying the latest scripts from S3 into your current CloudShell directory:
12+
13+
```bash
14+
aws s3 cp "s3://gap-setup-holding-page" . --recursive
15+
```
16+
17+
## Environments and IDs
18+
19+
| Environment | CloudFront distribution ID | Holding page S3 bucket | Holding page origin |
20+
|---|---|---|---|
21+
| `qa` | `E2YMATUXLSFFJV` | `gap-qa-holding-page` | `gap-qa-holding-page.s3-website.eu-west-2.amazonaws.com` |
22+
| `prod` | `E3GJQ1JB1DFNU4` | `gap-prod-holding-page` | `gap-prod-holding-page.s3-website.eu-west-2.amazonaws.com` |
23+
24+
## What the switch scripts change
25+
26+
`switch-to-holding-page.sh` updates these cache behaviors to point to the holding page origin:
27+
28+
- `/`
29+
- `/*`
30+
- `/grants/*`
31+
- `/apply/applicant`
32+
- `/apply/applicant/*`
33+
- `/apply/admin`
34+
- `/apply/admin/*`
35+
36+
It also:
37+
38+
- Forces those switched behaviors to use GET-only methods (`HEAD`, `GET`, `OPTIONS`)
39+
- Adds/overwrites a CloudFront custom error for `404 -> /index.html` with response code `200`
40+
- Creates a full cache invalidation for `/*`
41+
42+
`switch-to-live.sh` reverses this:
43+
44+
- Restores the switched behaviors to live origins (`find-lb` or `apply-lb` depending on path)
45+
- Restores allowed methods per behavior (`7 methods` for apply paths, `3 methods` for find paths)
46+
- Removes the `404 -> /index.html` custom error response
47+
- Creates a full cache invalidation for `/*`
48+
49+
Both switch scripts prompt for `qa` or `prod`, include explicit confirmation prompts, and create a timestamped backup file (`dist-backup-YYYYMMDD-HHMMSS.json`) before making changes.
50+
51+
## Scripts
52+
53+
### `s3/switch-to-holding-page.sh`
54+
55+
Switches selected paths to the S3 holding page for the chosen environment (`qa` or `prod`), then invalidates CloudFront.
56+
57+
```bash
58+
sh ./switch-to-holding-page.sh
59+
```
60+
61+
### `s3/switch-to-live.sh`
62+
63+
Restores selected paths to live load balancer origins for the chosen environment (`qa` or `prod`), then invalidates CloudFront.
64+
65+
```bash
66+
sh ./switch-to-live.sh
67+
```
68+
69+
### `s3/restore-from-backup.sh` - Be careful with this!
70+
71+
Restores from a backup file and invalidates CloudFront.
72+
Prompts for environment (`qa` or `prod`) before restoring.
73+
74+
```bash
75+
sh ./restore-from-backup.sh dist-backup-20260414-162948.json
76+
```
77+
78+
If run without an argument, it prints usage and available backup files.
79+
80+
### `s3/update-holding-page.sh`
81+
82+
Updates `holding-page/index.html`, uploads the generated page to the selected environment bucket (`qa` or `prod`), and invalidates `/index.html`.
83+
84+
What it prompts for:
85+
86+
- Environment (`qa`/`prod`)
87+
- Optional custom page message (defaults to `Please try again later.`)
88+
- Confirmation (plus an extra production warning prompt for `prod`)
89+
90+
```bash
91+
sh ./update-holding-page.sh
92+
```
93+
94+
### `s3/clear-cache-invalidate.sh`
95+
96+
Prompts for environment (`qa` or `prod`) and creates a full invalidation (`/*`) for that distribution.
97+
98+
```bash
99+
sh ./clear-cache-invalidate.sh
100+
```
101+
102+
## Suggested maintenance procedure
103+
104+
1. Update the holding page content first (optional):
105+
```bash
106+
sh ./update-holding-page.sh
107+
```
108+
2. Switch traffic to the holding page:
109+
```bash
110+
sh ./switch-to-holding-page.sh
111+
```
112+
3. Verify key URLs show the holding page.
113+
4. Perform maintenance.
114+
5. Switch traffic back to live:
115+
```bash
116+
sh ./switch-to-live.sh
117+
```
118+
6. Verify live traffic is restored.
119+
120+
## Recovery procedure
121+
122+
If needed, restore from a known backup file - Be very careful though!
123+
124+
```bash
125+
sh ./restore-from-backup.sh dist-backup-YYYYMMDD-HHMMSS.json
126+
```
127+
128+
Note: `restore-from-backup.sh` fetches the current ETag before update, so backup-file ETag staleness is not a problem.

aws/s3/clear-cache-invalidate.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# Prompt for environment
6+
while true; do
7+
read -rp "Which environment do you want to use? (qa/prod): " ENVIRONMENT
8+
case "$ENVIRONMENT" in
9+
qa|prod) break ;;
10+
*) echo "Invalid option. Please enter 'qa' or 'prod'." ;;
11+
esac
12+
done
13+
14+
# Set environment-specific values
15+
if [ "$ENVIRONMENT" = "prod" ]; then
16+
DIST_ID="E3GJQ1JB1DFNU4"
17+
else
18+
DIST_ID="E2YMATUXLSFFJV"
19+
fi
20+
21+
# Extra warning for prod
22+
if [ "$ENVIRONMENT" = "prod" ]; then
23+
echo ""
24+
echo "WARNING: You have selected the PRODUCTION environment. This will affect live users."
25+
read -rp "Are you sure you want to continue? (y/n): " PROD_CONFIRM
26+
if [ "$PROD_CONFIRM" != "y" ]; then
27+
echo "Aborted."
28+
exit 0
29+
fi
30+
fi
31+
32+
echo ""
33+
read -rp "You are about to create a full cache invalidation in the $ENVIRONMENT environment. Are you sure? (y/n): " CONFIRM
34+
if [ "$CONFIRM" != "y" ]; then
35+
echo "Aborted."
36+
exit 0
37+
fi
38+
39+
echo "Creating cache invalidation for $ENVIRONMENT..."
40+
INVALIDATION=$(aws cloudfront create-invalidation \
41+
--distribution-id "$DIST_ID" \
42+
--paths "/*" \
43+
--query 'Invalidation.Id' \
44+
--output text)
45+
echo "Invalidation created: $INVALIDATION"

aws/s3/holding-page/index.html

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<!DOCTYPE html>
2+
<html lang="en" class="govuk-template">
3+
4+
<head>
5+
<meta charset="utf-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
7+
<meta name="theme-color" content="#0b0c0c" />
8+
<title>Sorry, the service is unavailable – Find a grant</title>
9+
<link rel="stylesheet" type="text/css" href="https://test-env.find-a-grant-support-test.service.cabinetoffice.gov.uk/style.css" />
10+
</head>
11+
12+
<body class="govuk-template__body js-enabled">
13+
14+
<a href="#main-content" class="govuk-skip-link" data-module="govuk-skip-link">
15+
Skip to main content
16+
</a>
17+
18+
<header class="govuk-header" role="banner" data-module="govuk-header">
19+
<div class="govuk-header__container govuk-width-container">
20+
<div class="govuk-header__logo">
21+
<a href="https://www.gov.uk/" class="govuk-header__link govuk-header__link--homepage">
22+
<span class="govuk-header__logotype">
23+
<svg aria-hidden="true" focusable="false" class="govuk-header__logotype-crown"
24+
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 30" height="30" width="32">
25+
<path fill="currentColor" fill-rule="evenodd"
26+
d="M22.6 10.4c-1 .4-2-.1-2.4-1-.4-.9.1-2 1-2.4.9-.4 2 .1 2.4 1s-.1 2-1 2.4m-5.9 6.7c-.9.4-2-.1-2.4-1-.4-.9.1-2 1-2.4.9-.4 2 .1 2.4 1s-.1 2-1 2.4m10.8-3.7c-1 .4-2-.1-2.4-1-.4-.9.1-2 1-2.4.9-.4 2 .1 2.4 1s0 2-1 2.4m3.3 4.8c-1 .4-2-.1-2.4-1-.4-.9.1-2 1-2.4.9-.4 2 .1 2.4 1s-.1 2-1 2.4M17 4.7l2.3 1.2V2.5l-2.3.7-.2-.2.9-3h-3.4l.9 3-.2.2c-.1.1-2.3-.7-2.3-.7v3.4L15 4.7c.1.1.1.2.2.2l-1.3 4c-.1.2-.1.4-.1.6 0 1.1.8 2 1.9 2.2h.7c1-.2 1.9-1.1 1.9-2.1 0-.2 0-.4-.1-.6l-1.3-4c-.1-.2 0-.2.1-.3m-7.6 5.7c.9.4 2-.1 2.4-1 .4-.9-.1-2-1-2.4-.9-.4-2 .1-2.4 1s0 2 1 2.4m-5 3c.9.4 2-.1 2.4-1 .4-.9-.1-2-1-2.4-.9-.4-2 .1-2.4 1s.1 2 1 2.4m-3.2 4.8c.9.4 2-.1 2.4-1 .4-.9-.1-2-1-2.4-.9-.4-2 .1-2.4 1s0 2 1 2.4m14.8 11c4.4 0 8.6.3 12.3.8 1.1-4.5 2.4-7 3.7-8.8l-2.5-.9c.2 1.3.3 1.9 0 2.7-.4-.4-.8-1.1-1.1-2.3l-1.2 4c.7-.5 1.3-.8 2-.9-1.1 2.5-2.6 3.1-3.5 3-1.1-.2-1.7-1.2-1.5-2.1.3-1.2 1.5-1.5 2.1-.1 1.1-2.3-.8-3-2-2.3 1.9-1.9 2.1-3.5.6-5.6-2.1 1.6-2.1 3.2-1.2 5.5-1.2-1.4-3.2-.6-2.5 1.6.9-1.4 2.1-.5 1.9.8-.2 1.1-1.7 2.1-3.5 1.9-2.7-.2-2.9-2.1-2.9-3.6.7-.1 1.9.5 2.9 1.9l.4-4.3c-1.1 1.1-2.1 1.4-3.2 1.4.4-1.2 2.1-3 2.1-3h-5.4s1.7 1.9 2.1 3c-1.1 0-2.1-.2-3.2-1.4l.4 4.3c1-1.4 2.2-2 2.9-1.9-.1 1.5-.2 3.4-2.9 3.6-1.9.2-3.4-.8-3.5-1.9-.2-1.3 1-2.2 1.9-.8.7-2.3-1.2-3-2.5-1.6.9-2.2.9-3.9-1.2-5.5-1.5 2-1.3 3.7.6 5.6-1.2-.7-3.1 0-2 2.3.6-1.4 1.8-1.1 2.1.1.2.9-.3 1.9-1.5 2.1-.9.2-2.4-.5-3.5-3 .6 0 1.2.3 2 .9l-1.2-4c-.3 1.1-.7 1.9-1.1 2.3-.3-.8-.2-1.4 0-2.7l-2.9.9C1.3 23 2.6 25.5 3.7 30c3.7-.5 7.9-.8 12.3-.8">
27+
</path>
28+
</svg>
29+
<span class="govuk-header__logotype-text">GOV.UK</span>
30+
</span>
31+
</a>
32+
</div>
33+
<div class="govuk-header__content">
34+
<div class="govuk-heading-m gap-service-name">Find a grant</div>
35+
</div>
36+
</div>
37+
</header>
38+
39+
<div class="govuk-width-container">
40+
<main class="govuk-main-wrapper govuk-main-wrapper--l" id="main-content" role="main">
41+
<div class="govuk-grid-row">
42+
<div class="govuk-grid-column-two-thirds">
43+
<h1 class="govuk-heading-l">Sorry, the service is unavailable</h1>
44+
45+
<p class="govuk-body">Please try again later.</p>
46+
<!-- <p class="govuk-body">You will be able to use the service from 9am on Monday 19 November 2018.</p> -->
47+
48+
</div>
49+
</div>
50+
</main>
51+
</div>
52+
53+
<footer class="govuk-footer" role="contentinfo">
54+
<div class="govuk-width-container">
55+
<div class="govuk-footer__meta">
56+
<div class="govuk-footer__meta-item govuk-footer__meta-item--grow">
57+
58+
<svg aria-hidden="true" focusable="false" class="govuk-footer__licence-logo"
59+
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 483.2 195.7" height="17" width="41">
60+
<path fill="currentColor"
61+
d="M421.5 142.8V.1l-50.7 32.3v161.1h112.4v-50.7zm-122.3-9.6A47.12 47.12 0 0 1 221 97.8c0-26 21.1-47.1 47.1-47.1 16.7 0 31.4 8.7 39.7 21.8l42.7-27.2A97.63 97.63 0 0 0 268.1 0c-36.5 0-68.3 20.1-85.1 49.7A98 98 0 0 0 97.8 0C43.9 0 0 43.9 0 97.8s43.9 97.8 97.8 97.8c36.5 0 68.3-20.1 85.1-49.7a97.76 97.76 0 0 0 149.6 25.4l19.4 22.2h3v-87.8h-80l24.3 27.5zM97.8 145c-26 0-47.1-21.1-47.1-47.1s21.1-47.1 47.1-47.1 47.2 21 47.2 47S123.8 145 97.8 145" />
62+
</svg>
63+
64+
<span class="govuk-footer__licence-description">
65+
All content is available under the
66+
<a href="https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/"
67+
class="govuk-footer__link" rel="license">Open Government Licence v3.0</a>, except where otherwise stated
68+
</span>
69+
</div>
70+
71+
<div class="govuk-footer__meta-item">
72+
<a href="https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/"
73+
class="govuk-footer__link govuk-footer__copyright-logo">© Crown copyright</a>
74+
</div>
75+
</div>
76+
</div>
77+
</footer>
78+
</body>
79+
80+
</html>

0 commit comments

Comments
 (0)