cdk/lib/slo-monitoring.ts (95 lines of code) (raw):
import type { GuStackProps } from '@guardian/cdk/lib/constructs/core';
import { GuStack } from '@guardian/cdk/lib/constructs/core';
import { GuLambdaFunction } from '@guardian/cdk/lib/constructs/lambda';
import type { App } from 'aws-cdk-lib';
import { Duration } from 'aws-cdk-lib';
import { PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import { Queue } from 'aws-cdk-lib/aws-sqs';
import {
ParameterDataType,
ParameterTier,
StringParameter,
} from 'aws-cdk-lib/aws-ssm';
export class SloMonitoring extends GuStack {
constructor(scope: App, id: string, props: GuStackProps) {
super(scope, id, props);
const deadLetterQueue = new Queue(this, 'DeadLetterQueue', {
queueName: `notifications-slo-monitoring-dlq-${props.stage}`,
});
const queue = new Queue(this, 'MessageQueue', {
queueName: `notifications-slo-monitoring-${props.stage}`,
visibilityTimeout: Duration.minutes(6),
deadLetterQueue: {
queue: deadLetterQueue,
maxReceiveCount: 1,
},
});
// this advertises the url of the queue to the notifications app
new StringParameter(this, 'SenderQueueSSMParameter', {
parameterName: `/notifications/${props.stage}/mobile-notifications/notifications.queues.sloMonitoring`,
description:
'Queue for SLO Monitoring service. N.B. this parameter is created via cdk',
simpleName: false,
stringValue: queue.queueUrl,
tier: ParameterTier.STANDARD,
dataType: ParameterDataType.TEXT,
});
// this advertises the arn of the queue which can be used by the notifications app cloudformation
new StringParameter(this, 'SenderQueueSSMArnParameter', {
parameterName: `/notifications/${props.stage}/mobile-notifications/notifications.queues.sloMonitoringArn`,
description:
'Arn for the queue for SLO Monitoring service. N.B. this parameter is created via cdk',
simpleName: false,
stringValue: queue.queueArn,
tier: ParameterTier.STANDARD,
dataType: ParameterDataType.TEXT,
});
const sloMonitor = new GuLambdaFunction(this, 'SloMonitor', {
functionName: `mobile-notifications-slo-monitor-${props.stage}`,
fileName: 'slomonitor.jar',
handler: 'com.gu.notifications.slos.SloMonitor::handleMessage',
runtime: Runtime.JAVA_11,
app: 'slomonitor',
timeout: Duration.minutes(5),
});
const policies = [
new PolicyStatement({
actions: ['cloudwatch:PutMetricData'],
resources: ['*'],
}),
new PolicyStatement({
actions: [
'athena:StartQueryExecution',
'athena:GetQueryExecution',
'athena:GetQueryResults',
],
resources: ['*'],
}),
new PolicyStatement({
actions: ['glue:GetDatabase', 'glue:GetTable', 'glue:GetPartitions'],
resources: [
`arn:aws:glue:${this.region}:${this.account}:catalog`,
`arn:aws:glue:${this.region}:${this.account}:database/default`,
`arn:aws:glue:${this.region}:${this.account}:database/notifications`,
`arn:aws:glue:${this.region}:${this.account}:table/notifications/*`,
],
}),
new PolicyStatement({
actions: ['s3:Get*', 's3:List*'],
resources: [
`arn:aws:s3:::aws-mobile-event-logs-${props.stage.toLowerCase()}`,
`arn:aws:s3:::aws-mobile-event-logs-${props.stage.toLowerCase()}/*`,
],
}),
new PolicyStatement({
actions: ['s3:AbortMultipartUpload', 's3:PutObject'],
resources: [
`arn:aws:s3:::aws-mobile-event-logs-${props.stage.toLowerCase()}/athena/slo-monitoring/*`,
],
}),
];
policies.map((policy) => sloMonitor.addToRolePolicy(policy));
queue.grantConsumeMessages(sloMonitor);
sloMonitor.addEventSource(new SqsEventSource(queue, { batchSize: 1 }));
}
}