From dc1edac60837a68a81b9692de292f9cf64e87840 Mon Sep 17 00:00:00 2001 From: Eugene Cheung <81188333+echeung-amzn@users.noreply.github.com> Date: Fri, 6 Dec 2024 19:29:54 -0500 Subject: [PATCH] fix(MonitoringAspect): allow specifying CloudFrontDistribution and WafV2 alarms (#609) Fixes #607 Also replaces some things marked as deprecated in the unit tests just to make it less noisy. --- _By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license_ --- API.md | 66 ++++++ .../CloudFrontDistributionMonitoring.ts | 10 +- lib/monitoring/aws-wafv2/WafV2Monitoring.ts | 10 +- test/facade/MonitoringAspect.test.ts | 45 +++- .../MonitoringAspect.test.ts.snap | 192 +++++++++++++++++- 5 files changed, 296 insertions(+), 27 deletions(-) diff --git a/API.md b/API.md index c2b6bc70..87cd88fd 100644 --- a/API.md +++ b/API.md @@ -11043,6 +11043,10 @@ const cloudFrontDistributionMonitoringOptions: CloudFrontDistributionMonitoringO | addToDetailDashboard | boolean | Flag indicating if the widgets should be added to detailed dashboard. | | addToSummaryDashboard | boolean | Flag indicating if the widgets should be added to summary dashboard. | | useCreatedAlarms | IAlarmConsumer | Calls provided function to process all alarms created. | +| addError4xxRate | {[ key: string ]: ErrorRateThreshold} | *No description.* | +| addFault5xxRate | {[ key: string ]: ErrorRateThreshold} | *No description.* | +| addHighTpsAlarm | {[ key: string ]: HighTpsThreshold} | *No description.* | +| addLowTpsAlarm | {[ key: string ]: LowTpsThreshold} | *No description.* | --- @@ -11174,6 +11178,46 @@ Calls provided function to process all alarms created. --- +##### `addError4xxRate`Optional + +```typescript +public readonly addError4xxRate: {[ key: string ]: ErrorRateThreshold}; +``` + +- *Type:* {[ key: string ]: ErrorRateThreshold} + +--- + +##### `addFault5xxRate`Optional + +```typescript +public readonly addFault5xxRate: {[ key: string ]: ErrorRateThreshold}; +``` + +- *Type:* {[ key: string ]: ErrorRateThreshold} + +--- + +##### `addHighTpsAlarm`Optional + +```typescript +public readonly addHighTpsAlarm: {[ key: string ]: HighTpsThreshold}; +``` + +- *Type:* {[ key: string ]: HighTpsThreshold} + +--- + +##### `addLowTpsAlarm`Optional + +```typescript +public readonly addLowTpsAlarm: {[ key: string ]: LowTpsThreshold}; +``` + +- *Type:* {[ key: string ]: LowTpsThreshold} + +--- + ### CloudFrontDistributionMonitoringProps #### Initializer @@ -51753,6 +51797,8 @@ const wafV2MonitoringOptions: WafV2MonitoringOptions = { ... } | addToDetailDashboard | boolean | Flag indicating if the widgets should be added to detailed dashboard. | | addToSummaryDashboard | boolean | Flag indicating if the widgets should be added to summary dashboard. | | useCreatedAlarms | IAlarmConsumer | Calls provided function to process all alarms created. | +| addBlockedRequestsCountAlarm | {[ key: string ]: ErrorCountThreshold} | *No description.* | +| addBlockedRequestsRateAlarm | {[ key: string ]: ErrorRateThreshold} | *No description.* | --- @@ -51884,6 +51930,26 @@ Calls provided function to process all alarms created. --- +##### `addBlockedRequestsCountAlarm`Optional + +```typescript +public readonly addBlockedRequestsCountAlarm: {[ key: string ]: ErrorCountThreshold}; +``` + +- *Type:* {[ key: string ]: ErrorCountThreshold} + +--- + +##### `addBlockedRequestsRateAlarm`Optional + +```typescript +public readonly addBlockedRequestsRateAlarm: {[ key: string ]: ErrorRateThreshold}; +``` + +- *Type:* {[ key: string ]: ErrorRateThreshold} + +--- + ### WafV2MonitoringProps #### Initializer diff --git a/lib/monitoring/aws-cloudfront/CloudFrontDistributionMonitoring.ts b/lib/monitoring/aws-cloudfront/CloudFrontDistributionMonitoring.ts index 534970cc..95ada504 100644 --- a/lib/monitoring/aws-cloudfront/CloudFrontDistributionMonitoring.ts +++ b/lib/monitoring/aws-cloudfront/CloudFrontDistributionMonitoring.ts @@ -35,11 +35,7 @@ import { } from "../../dashboard"; export interface CloudFrontDistributionMonitoringOptions - extends BaseMonitoringProps {} - -export interface CloudFrontDistributionMonitoringProps - extends CloudFrontDistributionMetricFactoryProps, - CloudFrontDistributionMonitoringOptions { + extends BaseMonitoringProps { readonly addError4xxRate?: Record; readonly addFault5xxRate?: Record; @@ -47,6 +43,10 @@ export interface CloudFrontDistributionMonitoringProps readonly addHighTpsAlarm?: Record; } +export interface CloudFrontDistributionMonitoringProps + extends CloudFrontDistributionMetricFactoryProps, + CloudFrontDistributionMonitoringOptions {} + export class CloudFrontDistributionMonitoring extends Monitoring { readonly title: string; readonly distributionUrl?: string; diff --git a/lib/monitoring/aws-wafv2/WafV2Monitoring.ts b/lib/monitoring/aws-wafv2/WafV2Monitoring.ts index 4044f4b4..a99b5d51 100644 --- a/lib/monitoring/aws-wafv2/WafV2Monitoring.ts +++ b/lib/monitoring/aws-wafv2/WafV2Monitoring.ts @@ -28,15 +28,15 @@ import { MonitoringNamingStrategy, } from "../../dashboard"; -export interface WafV2MonitoringOptions extends BaseMonitoringProps {} - -export interface WafV2MonitoringProps - extends WafV2MetricFactoryProps, - WafV2MonitoringOptions { +export interface WafV2MonitoringOptions extends BaseMonitoringProps { readonly addBlockedRequestsCountAlarm?: Record; readonly addBlockedRequestsRateAlarm?: Record; } +export interface WafV2MonitoringProps + extends WafV2MetricFactoryProps, + WafV2MonitoringOptions {} + /** * Monitoring for AWS Web Application Firewall. * diff --git a/test/facade/MonitoringAspect.test.ts b/test/facade/MonitoringAspect.test.ts index 2cf1461b..ae0609ba 100644 --- a/test/facade/MonitoringAspect.test.ts +++ b/test/facade/MonitoringAspect.test.ts @@ -196,7 +196,18 @@ describe("MonitoringAspect", () => { }); // WHEN - facade.monitorScope(stack, defaultAspectProps); + facade.monitorScope(stack, { + ...defaultAspectProps, + cloudFront: { + props: { + addError4xxRate: { + Warning: { + maxErrorRate: 0.1, + }, + }, + }, + }, + }); // THEN expect(Template.fromStack(stack)).toMatchSnapshot(); @@ -402,7 +413,7 @@ describe("MonitoringAspect", () => { new lambda.Function(stack, "DummyFunction", { code: lambda.Code.fromInline("lambda"), handler: "index.handler", - runtime: lambda.Runtime.NODEJS_18_X, + runtime: lambda.Runtime.NODEJS_LATEST, }); // WHEN @@ -419,7 +430,7 @@ describe("MonitoringAspect", () => { new opensearch.Domain(stack, "DummyOSDomain", { domainName: "dummy-os-domain", - version: opensearch.EngineVersion.ELASTICSEARCH_7_10, + version: opensearch.EngineVersion.OPENSEARCH_2_15, }); new elasticsearch.Domain(stack, "DummyESDomain", { version: elasticsearch.ElasticsearchVersion.V7_10, @@ -558,11 +569,22 @@ describe("MonitoringAspect", () => { code: synthetics.Code.fromInline("/* nothing */"), handler: "index.handler", }), - runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_5_1, + runtime: synthetics.Runtime.SYNTHETICS_NODEJS_PUPPETEER_9_0, }); // WHEN - facade.monitorScope(stack, defaultAspectProps); + facade.monitorScope(stack, { + ...defaultAspectProps, + syntheticsCanaries: { + props: { + add4xxErrorCountAlarm: { + Warning: { + maxErrorCount: 0, + }, + }, + }, + }, + }); // THEN expect(Template.fromStack(stack)).toMatchSnapshot(); @@ -584,7 +606,18 @@ describe("MonitoringAspect", () => { }); // WHEN - facade.monitorScope(stack, defaultAspectProps); + facade.monitorScope(stack, { + ...defaultAspectProps, + webApplicationFirewallAclV2: { + props: { + addBlockedRequestsCountAlarm: { + Warning: { + maxErrorCount: 0, + }, + }, + }, + }, + }); // THEN expect(Template.fromStack(stack)).toMatchSnapshot(); diff --git a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap index fd828298..bf3f6fe8 100644 --- a/test/facade/__snapshots__/MonitoringAspect.test.ts.snap +++ b/test/facade/__snapshots__/MonitoringAspect.test.ts.snap @@ -1631,7 +1631,7 @@ Object { ], }, "Name": "canary", - "RuntimeVersion": "syn-nodejs-puppeteer-5.1", + "RuntimeVersion": "syn-nodejs-puppeteer-9.0", "Schedule": Object { "DurationInSeconds": "0", "Expression": "rate(5 minutes)", @@ -1803,7 +1803,25 @@ Object { }, "DashboardFactoryAlarmDashboard6286FAD3": Object { "Properties": Object { - "DashboardBody": "{\\"start\\":\\"-PT8H\\",\\"periodOverride\\":\\"inherit\\",\\"widgets\\":[]}", + "DashboardBody": Object { + "Fn::Join": Array [ + "", + Array [ + "{\\"start\\":\\"-PT8H\\",\\"periodOverride\\":\\"inherit\\",\\"widgets\\":[{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Canary Error-Count Warning\\",\\"region\\":\\"", + Object { + "Ref": "AWS::Region", + }, + "\\",\\"annotations\\":{\\"alarms\\":[\\"", + Object { + "Fn::GetAtt": Array [ + "MonitoringFacadeDummyMonitoringCanaryErrorCountWarningD27BFCF7", + "Arn", + ], + }, + "\\"]},\\"yAxis\\":{}}}]}", + ], + ], + }, "DashboardName": "DummyDashboard-Alarms", }, "Type": "AWS::CloudWatch::Dashboard", @@ -1834,7 +1852,7 @@ Object { Object { "Ref": "Canary11957FE2", }, - "\\",{\\"label\\":\\"5xx\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors (rate)\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"5xx\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"4xx > 0 for 3 datapoints within 15 minutes\\",\\"value\\":0,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors (rate)\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -1896,7 +1914,7 @@ Object { Object { "Ref": "Canary11957FE2", }, - "\\",{\\"label\\":\\"5xx\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":6,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors (rate)\\",\\"region\\":\\"", + "\\",{\\"label\\":\\"5xx\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"4xx > 0 for 3 datapoints within 15 minutes\\",\\"value\\":0,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":6,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Errors (rate)\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -1940,6 +1958,42 @@ Object { }, "Type": "AWS::CloudWatch::Dashboard", }, + "MonitoringFacadeDummyMonitoringCanaryErrorCountWarningD27BFCF7": Object { + "Properties": Object { + "ActionsEnabled": true, + "AlarmDescription": "Error count is too high.", + "AlarmName": "DummyMonitoring-Canary-Error-Count-Warning", + "ComparisonOperator": "GreaterThanThreshold", + "DatapointsToAlarm": 3, + "EvaluationPeriods": 3, + "Metrics": Array [ + Object { + "Id": "m1", + "Label": "4xx", + "MetricStat": Object { + "Metric": Object { + "Dimensions": Array [ + Object { + "Name": "CanaryName", + "Value": Object { + "Ref": "Canary11957FE2", + }, + }, + ], + "MetricName": "4xx", + "Namespace": "CloudWatchSynthetics", + }, + "Period": 300, + "Stat": "Sum", + }, + "ReturnData": true, + }, + ], + "Threshold": 0, + "TreatMissingData": "notBreaching", + }, + "Type": "AWS::CloudWatch::Alarm", + }, }, "Rules": Object { "CheckBootstrapVersion": Object { @@ -2027,7 +2081,25 @@ Object { }, "DashboardFactoryAlarmDashboard6286FAD3": Object { "Properties": Object { - "DashboardBody": "{\\"start\\":\\"-PT8H\\",\\"periodOverride\\":\\"inherit\\",\\"widgets\\":[]}", + "DashboardBody": Object { + "Fn::Join": Array [ + "", + Array [ + "{\\"start\\":\\"-PT8H\\",\\"periodOverride\\":\\"inherit\\",\\"widgets\\":[{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Distribution Error-Rate Warning\\",\\"region\\":\\"", + Object { + "Ref": "AWS::Region", + }, + "\\",\\"annotations\\":{\\"alarms\\":[\\"", + Object { + "Fn::GetAtt": Array [ + "MonitoringFacadeDummyMonitoringDistributionErrorRateWarning8714796D", + "Arn", + ], + }, + "\\"]},\\"yAxis\\":{}}}]}", + ], + ], + }, "DashboardName": "DummyDashboard-Alarms", }, "Type": "AWS::CloudWatch::Dashboard", @@ -2106,7 +2178,7 @@ Object { Object { "Ref": "Distribution830FAC52", }, - "\\",\\"Region\\",\\"Global\\",{\\"label\\":\\"5XX\\",\\"region\\":\\"us-east-1\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", + "\\",\\"Region\\",\\"Global\\",{\\"label\\":\\"5XX\\",\\"region\\":\\"us-east-1\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"4XX > 0.1 for 3 datapoints within 15 minutes\\",\\"value\\":0.1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", ], ], }, @@ -2168,7 +2240,7 @@ Object { Object { "Ref": "Distribution830FAC52", }, - "\\",\\"Region\\",\\"Global\\",{\\"label\\":\\"5XX\\",\\"region\\":\\"us-east-1\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", + "\\",\\"Region\\",\\"Global\\",{\\"label\\":\\"5XX\\",\\"region\\":\\"us-east-1\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"4XX > 0.1 for 3 datapoints within 15 minutes\\",\\"value\\":0.1,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Rate\\",\\"showUnits\\":false}}}}]}", ], ], }, @@ -2224,6 +2296,46 @@ Object { }, "Type": "AWS::CloudFront::CloudFrontOriginAccessIdentity", }, + "MonitoringFacadeDummyMonitoringDistributionErrorRateWarning8714796D": Object { + "Properties": Object { + "ActionsEnabled": true, + "AlarmDescription": "Error rate is too high.", + "AlarmName": "DummyMonitoring-Distribution-Error-Rate-Warning", + "ComparisonOperator": "GreaterThanThreshold", + "DatapointsToAlarm": 3, + "EvaluationPeriods": 3, + "Metrics": Array [ + Object { + "Id": "m1", + "Label": "4XX", + "MetricStat": Object { + "Metric": Object { + "Dimensions": Array [ + Object { + "Name": "DistributionId", + "Value": Object { + "Ref": "Distribution830FAC52", + }, + }, + Object { + "Name": "Region", + "Value": "Global", + }, + ], + "MetricName": "4xxErrorRate", + "Namespace": "AWS/CloudFront", + }, + "Period": 300, + "Stat": "Average", + }, + "ReturnData": true, + }, + ], + "Threshold": 0.1, + "TreatMissingData": "notBreaching", + }, + "Type": "AWS::CloudWatch::Alarm", + }, }, "Rules": Object { "CheckBootstrapVersion": Object { @@ -6549,7 +6661,7 @@ Object { "EncryptionAtRestOptions": Object { "Enabled": false, }, - "EngineVersion": "Elasticsearch_7.10", + "EngineVersion": "OpenSearch_2.15", "LogPublishingOptions": Object {}, "NodeToNodeEncryptionOptions": Object { "Enabled": false, @@ -9091,7 +9203,25 @@ Object { "Resources": Object { "DashboardFactoryAlarmDashboard6286FAD3": Object { "Properties": Object { - "DashboardBody": "{\\"start\\":\\"-PT8H\\",\\"periodOverride\\":\\"inherit\\",\\"widgets\\":[]}", + "DashboardBody": Object { + "Fn::Join": Array [ + "", + Array [ + "{\\"start\\":\\"-PT8H\\",\\"periodOverride\\":\\"inherit\\",\\"widgets\\":[{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"DummyAcl Blocked-Count Warning\\",\\"region\\":\\"", + Object { + "Ref": "AWS::Region", + }, + "\\",\\"annotations\\":{\\"alarms\\":[\\"", + Object { + "Fn::GetAtt": Array [ + "MonitoringFacadeDummyMonitoringDummyAclBlockedCountWarning271BD25D", + "Arn", + ], + }, + "\\"]},\\"yAxis\\":{}}}]}", + ], + ], + }, "DashboardName": "DummyDashboard-Alarms", }, "Type": "AWS::CloudWatch::Dashboard", @@ -9118,7 +9248,7 @@ Object { Object { "Ref": "AWS::Region", }, - "\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests (rate)\\",\\"region\\":\\"", + "\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Blocked > 0 for 3 datapoints within 15 minutes\\",\\"value\\":0,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":5,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests (rate)\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -9160,7 +9290,7 @@ Object { Object { "Ref": "AWS::Region", }, - "\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests (rate)\\",\\"region\\":\\"", + "\\",\\"Rule\\",\\"ALL\\",{\\"label\\":\\"Blocked\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Blocked > 0 for 3 datapoints within 15 minutes\\",\\"value\\":0,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Blocked Requests (rate)\\",\\"region\\":\\"", Object { "Ref": "AWS::Region", }, @@ -9194,6 +9324,46 @@ Object { }, "Type": "AWS::WAFv2::WebACL", }, + "MonitoringFacadeDummyMonitoringDummyAclBlockedCountWarning271BD25D": Object { + "Properties": Object { + "ActionsEnabled": true, + "AlarmDescription": "Blocked count is too high.", + "AlarmName": "DummyMonitoring-DummyAcl-Blocked-Count-Warning", + "ComparisonOperator": "GreaterThanThreshold", + "DatapointsToAlarm": 3, + "EvaluationPeriods": 3, + "Metrics": Array [ + Object { + "Id": "m1", + "Label": "Blocked", + "MetricStat": Object { + "Metric": Object { + "Dimensions": Array [ + Object { + "Name": "Region", + "Value": Object { + "Ref": "AWS::Region", + }, + }, + Object { + "Name": "Rule", + "Value": "ALL", + }, + ], + "MetricName": "BlockedRequests", + "Namespace": "AWS/WAFV2", + }, + "Period": 300, + "Stat": "Sum", + }, + "ReturnData": true, + }, + ], + "Threshold": 0, + "TreatMissingData": "notBreaching", + }, + "Type": "AWS::CloudWatch::Alarm", + }, }, "Rules": Object { "CheckBootstrapVersion": Object {