diff --git a/cdk/lib/__snapshots__/prism.test.ts.snap b/cdk/lib/__snapshots__/prism.test.ts.snap index 3da83d08..942e3521 100644 --- a/cdk/lib/__snapshots__/prism.test.ts.snap +++ b/cdk/lib/__snapshots__/prism.test.ts.snap @@ -1011,6 +1011,20 @@ exports[`The PrismEc2App stack matches the snapshot 1`] = ` "EvaluationPeriods": 60, "MetricName": "UnHealthyHostCount", "Namespace": "AWS/ApplicationELB", + "OKActions": [ + { + "Fn::Join": [ + "", + [ + "arn:aws:sns:eu-west-1:", + { + "Ref": "AWS::AccountId", + }, + ":devx-alerts", + ], + ], + }, + ], "Period": 60, "Statistic": "Maximum", "Tags": [ diff --git a/cdk/lib/prism.ts b/cdk/lib/prism.ts index 49ee1da1..c5a289dc 100644 --- a/cdk/lib/prism.ts +++ b/cdk/lib/prism.ts @@ -1,4 +1,5 @@ import { AccessScope } from '@guardian/cdk/lib/constants'; +import { GuUnhealthyInstancesAlarm } from '@guardian/cdk/lib/constructs/cloudwatch'; import { GuDistributionBucketParameter, GuPrivateConfigBucketParameter, @@ -18,6 +19,7 @@ import { BlockDeviceVolume, EbsDeviceVolumeType, } from 'aws-cdk-lib/aws-autoscaling'; +import { SnsAction } from 'aws-cdk-lib/aws-cloudwatch-actions'; import { InstanceClass, InstanceSize, @@ -26,6 +28,7 @@ import { UserData, } from 'aws-cdk-lib/aws-ec2'; import { Bucket } from 'aws-cdk-lib/aws-s3'; +import { Topic } from 'aws-cdk-lib/aws-sns'; interface PrismProps extends Omit { domainName: string; @@ -51,7 +54,8 @@ export class Prism extends GuStack { }); const { buildIdentifier, instanceMetricGranularity } = props; - const { stack, stage } = this; + const { stack, stage, region, account } = this; + const snsTopicName = 'devx-alerts'; const distBucket = Bucket.fromBucketName( this, @@ -98,7 +102,7 @@ export class Prism extends GuStack { monitoringConfiguration: this.stage === 'PROD' ? { - snsTopicName: 'devx-alerts', + snsTopicName, http5xxAlarm: false, unhealthyInstancesAlarm: true, } @@ -154,5 +158,23 @@ export class Prism extends GuStack { const cfnAsg = pattern.autoScalingGroup.node .defaultChild as CfnAutoScalingGroup; cfnAsg.healthCheckGracePeriod = Duration.minutes(15).toSeconds(); + + // Configure OK action to receive a notification once alarm has resolved. + // TODO Set the OK action at the construct level within GuCDK + const maybeUnhealthyInstanceAlarm = this.node.children.filter( + (child): child is GuUnhealthyInstancesAlarm => + child instanceof GuUnhealthyInstancesAlarm, + ); + if (maybeUnhealthyInstanceAlarm.length > 0) { + const snsTopic = Topic.fromTopicArn( + this, + `SnsTopic`, + `arn:aws:sns:${region}:${account}:${snsTopicName}`, + ); + + maybeUnhealthyInstanceAlarm.forEach((alarm) => { + alarm.addOkAction(new SnsAction(snsTopic)); + }); + } } }