Skip to content

Commit

Permalink
Add dummy heartbeat file, so that 200 is always returned. (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
EarthlingDavey authored Jan 10, 2025
1 parent afa0384 commit 69a1e46
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 4 deletions.
8 changes: 8 additions & 0 deletions conf/local.Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# A local mock CDN to proxy requests to the Minio (S3) server.
# Mimics AWS CloudFront, and removes the bucket path from the URL.
# e.g. Request: http://archive.intranet.docker/intranet.justice.gov.uk/hmcts/2024-12-13/index.html
# proxies to : http://minio:9000/bucket-name/intranet.justice.gov.uk/hmcts/2024-12-13/index.html

:2019
rewrite * /{$S3_BUCKET_NAME}{uri}
reverse_proxy minio:9000
6 changes: 6 additions & 0 deletions conf/node/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export const sensitiveFiles = [
`hts-cache/new.zip`,
];

/**
* Intranet application
*/

export const heartbeatEndpoint = "auth/heartbeat";

/**
* Index pages
*/
Expand Down
5 changes: 4 additions & 1 deletion conf/node/controllers/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
getHttrackProgress,
waitForHttrackComplete,
} from "./httrack.js";
import { createHeartbeat, sync, writeToS3 } from "./s3.js";
import { generateRootIndex, generateAgencyIndex } from "./generate-indexes.js";
import { sync, writeToS3 } from "./s3.js";

/**
*
Expand Down Expand Up @@ -49,6 +49,9 @@ export const main = async ({ url, agency, depth }) => {
sensitiveFiles.map((file) => fs.rm(`${paths.fs}/${file}`, { force: true })),
);

// Add a file at /auth/heartbeat for the intranet's heartbeat script.
await createHeartbeat();

// Sync the snapshot to S3
await sync(paths.fs, `s3://${s3BucketName}/${paths.s3}`);

Expand Down
18 changes: 18 additions & 0 deletions conf/node/controllers/main.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,24 @@ describe("main", () => {
expect(pathExists).toBe(false);
}, 10_000);

it("should create an auth/heartbeat file", async () => {
await main({ url, agency, depth: 1 });

// The snapshot should be on s3
const objects = await s3Client.send(
new ListObjectsV2Command({
Bucket: s3BucketName,
Prefix: 'auth/heartbeat',
}),
);

const heartbeat = objects.Contents.find(
(object) => object.Key === 'auth/heartbeat',
);

expect(heartbeat).toBeDefined();
}, 10_000);

it("should create root and agency index files", async () => {
await main({ url, agency, depth: 1 });

Expand Down
31 changes: 31 additions & 0 deletions conf/node/controllers/s3.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
s3BucketName,
s3Credentials as credentials,
s3Region,
heartbeatEndpoint
} from "../constants.js";

/**
Expand Down Expand Up @@ -34,6 +35,36 @@ export const s3Options = {

export const client = new S3Client(s3Options);

/**
* Create dummy /auth/heartbeat at bucket root, if it doesn't exist.
*
* @param {string} bucket - The bucket name, defaults to the s3BucketName constant
* @returns {Promise<void>}
*
* @throws {Error}
*/

export const createHeartbeat = async (bucket = s3BucketName, file = heartbeatEndpoint) => {
const objects = await client.send(
new ListObjectsV2Command({
Bucket: bucket,
Prefix: file,
}),
)

if (!objects.Contents?.length) {
const response = await client.send(
new PutObjectCommand({
Bucket: bucket,
Key: file,
Body: "OK",
})
)
}

return;
};

/**
* S3 sync client
*
Expand Down
24 changes: 24 additions & 0 deletions conf/node/controllers/s3.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { s3BucketName } from "../constants.js";
import {
s3Options,
checkAccess,
createHeartbeat,
sync,
s3EmptyDir,
writeToS3,
Expand All @@ -35,6 +36,29 @@ describe("checkAccess", () => {
});
});

describe("createHeartbeat", () => {
let client;

beforeAll(() => {
client = new S3Client(s3Options);
});

it("should create /auth/heartbeat if it doesn't exist", async () => {
await s3EmptyDir("test/auth");

await createHeartbeat(undefined, "test/auth/heartbeat");

const objects = await client.send(
new ListObjectsV2Command({
Bucket: s3BucketName,
Prefix: "test/auth/heartbeat",
}),
);

expect(objects.Contents.length).toBe(1);
});
});

describe("sync", () => {
let client;

Expand Down
14 changes: 11 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ services:
environment:
MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID}
MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY}
# Accessible at this domain, so we can manually check that CloudFront cookies have been set correctly.
VIRTUAL_HOST: archive.intranet.docker
VIRTUAL_PORT: "9001"
command: server --console-address ":9001" /data
healthcheck:
test: timeout 5s bash -c ':> /dev/tcp/127.0.0.1/9000' || exit 1
Expand All @@ -58,3 +55,14 @@ services:
mc anonymous set download intranet-archive/${S3_BUCKET_NAME};
exit 0
"
cdn:
image: caddy:2-alpine
volumes:
- ./conf/local.Caddyfile:/etc/caddy/Caddyfile
environment:
S3_BUCKET_NAME: ${S3_BUCKET_NAME}
VIRTUAL_HOST: archive.intranet.docker
VIRTUAL_PORT: 2019
depends_on:
- minio

0 comments on commit 69a1e46

Please sign in to comment.