Skip to content

Commit 82410cf

Browse files
authored
Merge branch 'main' into CCM-12995_AddingEventPubInfra
2 parents b1c5fa1 + c30a571 commit 82410cf

File tree

20 files changed

+304
-20
lines changed

20 files changed

+304
-20
lines changed

infrastructure/terraform/components/api/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ No requirements.
3939
| <a name="module_get_letter"></a> [get\_letter](#module\_get\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
4040
| <a name="module_get_letter_data"></a> [get\_letter\_data](#module\_get\_letter\_data) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
4141
| <a name="module_get_letters"></a> [get\_letters](#module\_get\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
42+
| <a name="module_get_status"></a> [get\_status](#module\_get\_status) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
4243
| <a name="module_kms"></a> [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.20/terraform-kms.zip | n/a |
4344
| <a name="module_letter_status_update"></a> [letter\_status\_update](#module\_letter\_status\_update) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a |
4445
| <a name="module_letter_status_updates_queue"></a> [letter\_status\_updates\_queue](#module\_letter\_status\_updates\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a |

infrastructure/terraform/components/api/iam_role_api_gateway_execution_role.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ data "aws_iam_policy_document" "api_gateway_execution_policy" {
5454
module.get_letters.function_arn,
5555
module.patch_letter.function_arn,
5656
module.post_letters.function_arn,
57+
module.get_status.function_arn,
5758
module.post_mi.function_arn
5859
]
5960
}

infrastructure/terraform/components/api/locals.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ locals {
1111
GET_LETTER_LAMBDA_ARN = module.get_letter.function_arn
1212
GET_LETTERS_LAMBDA_ARN = module.get_letters.function_arn
1313
GET_LETTER_DATA_LAMBDA_ARN = module.get_letter_data.function_arn
14+
GET_STATUS_LAMBDA_ARN = module.get_status.function_arn
1415
PATCH_LETTER_LAMBDA_ARN = module.patch_letter.function_arn
1516
POST_LETTERS_LAMBDA_ARN = module.post_letters.function_arn
1617
POST_MI_LAMBDA_ARN = module.post_mi.function_arn
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
module "get_status" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip"
3+
4+
function_name = "get_status"
5+
description = "Healthcheck for service"
6+
7+
aws_account_id = var.aws_account_id
8+
component = var.component
9+
environment = var.environment
10+
project = var.project
11+
region = var.region
12+
group = var.group
13+
14+
log_retention_in_days = var.log_retention_in_days
15+
kms_key_arn = module.kms.key_arn
16+
17+
iam_policy_document = {
18+
body = data.aws_iam_policy_document.get_status_lambda.json
19+
}
20+
21+
function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"]
22+
function_code_base_path = local.aws_lambda_functions_dir_path
23+
function_code_dir = "api-handler/dist"
24+
function_include_common = true
25+
handler_function_name = "getStatus"
26+
runtime = "nodejs22.x"
27+
memory = 128
28+
timeout = 5
29+
log_level = var.log_level
30+
31+
force_lambda_code_deploy = var.force_lambda_code_deploy
32+
enable_lambda_insights = false
33+
34+
send_to_firehose = true
35+
log_destination_arn = local.destination_arn
36+
log_subscription_role_arn = local.acct.log_subscription_role_arn
37+
38+
lambda_env_vars = merge(local.common_lambda_env_vars, {})
39+
}
40+
41+
data "aws_iam_policy_document" "get_status_lambda" {
42+
statement {
43+
sid = "KMSPermissions"
44+
effect = "Allow"
45+
46+
actions = [
47+
"kms:Decrypt",
48+
"kms:GenerateDataKey",
49+
]
50+
51+
resources = [
52+
module.kms.key_arn, ## Requires shared kms module
53+
]
54+
}
55+
56+
statement {
57+
sid = "AllowDynamoDBAccess"
58+
effect = "Allow"
59+
60+
actions = [
61+
"dynamodb:DescribeTable"
62+
]
63+
64+
resources = [
65+
aws_dynamodb_table.letters.arn,
66+
"${aws_dynamodb_table.letters.arn}/index/supplierStatus-index"
67+
]
68+
}
69+
70+
71+
statement {
72+
sid = "S3ListAllMyBuckets"
73+
actions = ["s3:ListAllMyBuckets"]
74+
resources = ["arn:aws:s3:::*"]
75+
}
76+
}

infrastructure/terraform/components/api/resources/spec.tmpl.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,34 @@
2323
},
2424
"openapi": "3.0.1",
2525
"paths": {
26+
"/_status": {
27+
"get": {
28+
"operationId": "getStatusId",
29+
"responses": {
30+
"200": {
31+
"description": "OK"
32+
},
33+
"500": {
34+
"description": "Server error"
35+
}
36+
},
37+
"summary": "Healthcheck endpoint",
38+
"x-amazon-apigateway-integration": {
39+
"contentHandling": "CONVERT_TO_TEXT",
40+
"credentials": "${APIG_EXECUTION_ROLE_ARN}",
41+
"httpMethod": "POST",
42+
"passthroughBehavior": "WHEN_NO_TEMPLATES",
43+
"responses": {
44+
".*": {
45+
"statusCode": "200"
46+
}
47+
},
48+
"timeoutInMillis": 29000,
49+
"type": "AWS_PROXY",
50+
"uri": "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${GET_STATUS_LAMBDA_ARN}/invocations"
51+
}
52+
}
53+
},
2654
"/letters": {
2755
"get": {
2856
"description": "Returns 200 OK with paginated letter ids.",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
2+
import { DBHealthcheck } from "../healthcheck";
3+
import { createTables, DBContext, deleteTables, setupDynamoDBContainer } from "./db";
4+
5+
// Database tests can take longer, especially with setup and teardown
6+
jest.setTimeout(30000);
7+
8+
describe('DBHealthcheck', () => {
9+
10+
let db: DBContext;
11+
12+
beforeAll(async () => {
13+
db = await setupDynamoDBContainer();
14+
});
15+
16+
beforeEach(async () => {
17+
await createTables(db);
18+
});
19+
20+
afterEach(async () => {
21+
await deleteTables(db);
22+
});
23+
24+
it('passes when the database is available', async () => {
25+
const dbHealthCheck = new DBHealthcheck(db.docClient, db.config);
26+
await dbHealthCheck.check();
27+
});
28+
29+
it('fails when the database is unavailable', async () => {
30+
const realFunction = db.docClient.send;
31+
db.docClient.send = jest.fn().mockImplementation(() => { throw new Error('Failed to send')});
32+
33+
const dbHealthCheck = new DBHealthcheck(db.docClient, db.config);
34+
await expect(dbHealthCheck.check()).rejects.toThrow();
35+
36+
db.docClient.send = realFunction;
37+
});
38+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { DescribeTableCommand } from "@aws-sdk/client-dynamodb";
2+
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
3+
import { LetterRepositoryConfig } from "./letter-repository";
4+
5+
export class DBHealthcheck {
6+
constructor(readonly ddbClient: DynamoDBDocumentClient,
7+
readonly config: LetterRepositoryConfig) {}
8+
9+
async check(): Promise<void> {
10+
await this.ddbClient.send(new DescribeTableCommand({
11+
TableName: this.config.lettersTableName}));
12+
}
13+
}

internal/datastore/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ export * from './types';
22
export * from './mi-repository';
33
export * from './letter-repository';
44
export * from './supplier-repository';
5+
export * from './healthcheck';
56
export * from './types';

lambdas/api-handler/src/config/__tests__/deps.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import type { Deps } from '../deps';
32

43
describe('createDependenciesContainer', () => {
@@ -40,6 +39,7 @@ describe('createDependenciesContainer', () => {
4039
jest.mock('@internal/datastore', () => ({
4140
LetterRepository: jest.fn(),
4241
MIRepository: jest.fn(),
42+
DBHealthcheck: jest.fn()
4343
}));
4444

4545
// Env

lambdas/api-handler/src/config/deps.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
33
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
44
import { SQSClient } from "@aws-sdk/client-sqs";
55
import pino from 'pino';
6-
import { LetterRepository, MIRepository } from '../../../../internal/datastore';
6+
import { LetterRepository, MIRepository, DBHealthcheck } from '@internal/datastore';
77
import { envVars, EnvVars } from "../config/env";
88

99
export type Deps = {
1010
s3Client: S3Client;
1111
sqsClient: SQSClient;
1212
letterRepo: LetterRepository;
1313
miRepo: MIRepository;
14+
dbHealthcheck: DBHealthcheck;
1415
logger: pino.Logger;
1516
env: EnvVars
1617
};
@@ -20,6 +21,7 @@ function createDocumentClient(): DynamoDBDocumentClient {
2021
return DynamoDBDocumentClient.from(ddbClient);
2122
}
2223

24+
2325
function createLetterRepository(log: pino.Logger, envVars: EnvVars): LetterRepository {
2426

2527
const config = {
@@ -30,6 +32,15 @@ function createLetterRepository(log: pino.Logger, envVars: EnvVars): LetterRepos
3032
return new LetterRepository(createDocumentClient(), log, config);
3133
}
3234

35+
function createDBHealthcheck(envVars: EnvVars): DBHealthcheck {
36+
const config = {
37+
lettersTableName: envVars.LETTERS_TABLE_NAME,
38+
lettersTtlHours: envVars.LETTER_TTL_HOURS
39+
};
40+
41+
return new DBHealthcheck(createDocumentClient(), config);
42+
}
43+
3344
function createMIRepository(log: pino.Logger, envVars: EnvVars): MIRepository {
3445

3546
const config = {
@@ -49,6 +60,7 @@ export function createDependenciesContainer(): Deps {
4960
sqsClient: new SQSClient(),
5061
letterRepo: createLetterRepository(log, envVars),
5162
miRepo: createMIRepository(log, envVars),
63+
dbHealthcheck: createDBHealthcheck(envVars),
5264
logger: log,
5365
env: envVars
5466
};

0 commit comments

Comments
 (0)