diff --git a/API.md b/API.md
index 4ad62148..f8f581c3 100644
--- a/API.md
+++ b/API.md
@@ -1097,6 +1097,7 @@ new MonitoringFacade(scope: Construct, id: string, props?: MonitoringFacadeProps
| monitorQueueProcessingEc2Service
| *No description.* |
| monitorQueueProcessingFargateService
| *No description.* |
| monitorRdsCluster
| *No description.* |
+| monitorRdsInstance
| *No description.* |
| monitorRedshiftCluster
| *No description.* |
| monitorS3Bucket
| *No description.* |
| monitorScope
| Uses an aspect to automatically monitor all resources in the given scope. |
@@ -1828,6 +1829,18 @@ public monitorRdsCluster(props: RdsClusterMonitoringProps): MonitoringFacade
---
+##### `monitorRdsInstance`
+
+```typescript
+public monitorRdsInstance(props: RdsInstanceMonitoringProps): MonitoringFacade
+```
+
+###### `props`Required
+
+- *Type:* RdsInstanceMonitoringProps
+
+---
+
##### `monitorRedshiftCluster`
```typescript
@@ -33045,6 +33058,8 @@ const monitoringAspectProps: MonitoringAspectProps = { ... }
| lambda
| MonitoringAspectType
| *No description.* |
| openSearch
| MonitoringAspectType
| *No description.* |
| rds
| MonitoringAspectType
| *No description.* |
+| rdsCluster
| MonitoringAspectType
| *No description.* |
+| rdsInstance
| MonitoringAspectType
| *No description.* |
| redshift
| MonitoringAspectType
| *No description.* |
| s3
| MonitoringAspectType
| *No description.* |
| secretsManager
| MonitoringAspectType
| *No description.* |
@@ -33246,7 +33261,9 @@ public readonly openSearch: MonitoringAspectType;
---
-##### `rds`Optional
+##### ~~`rds`~~Optional
+
+- *Deprecated:* Use rdsCluster instead.
```typescript
public readonly rds: MonitoringAspectType;
@@ -33256,6 +33273,26 @@ public readonly rds: MonitoringAspectType;
---
+##### `rdsCluster`Optional
+
+```typescript
+public readonly rdsCluster: MonitoringAspectType;
+```
+
+- *Type:* MonitoringAspectType
+
+---
+
+##### `rdsInstance`Optional
+
+```typescript
+public readonly rdsInstance: MonitoringAspectType;
+```
+
+- *Type:* MonitoringAspectType
+
+---
+
##### `redshift`Optional
```typescript
@@ -38090,6 +38127,381 @@ public readonly addMinConnectionCountAlarm: {[ key: string ]: LowConnectionCount
---
+### RdsInstanceMetricFactoryProps
+
+#### Initializer
+
+```typescript
+import { RdsInstanceMetricFactoryProps } from 'cdk-monitoring-constructs'
+
+const rdsInstanceMetricFactoryProps: RdsInstanceMetricFactoryProps = { ... }
+```
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| instance
| aws-cdk-lib.aws_rds.IDatabaseInstance
| database instance. |
+
+---
+
+##### `instance`Required
+
+```typescript
+public readonly instance: IDatabaseInstance;
+```
+
+- *Type:* aws-cdk-lib.aws_rds.IDatabaseInstance
+
+database instance.
+
+---
+
+### RdsInstanceMonitoringOptions
+
+#### Initializer
+
+```typescript
+import { RdsInstanceMonitoringOptions } from 'cdk-monitoring-constructs'
+
+const rdsInstanceMonitoringOptions: RdsInstanceMonitoringOptions = { ... }
+```
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| alarmFriendlyName
| string
| Plain name, used in naming alarms. |
+| humanReadableName
| string
| Human-readable name is a freeform string, used as a caption or description. |
+| localAlarmNamePrefixOverride
| string
| If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value. |
+| addToAlarmDashboard
| boolean
| Flag indicating if the widgets should be added to alarm dashboard. |
+| 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. |
+| addCpuUsageAlarm
| {[ key: string ]: UsageThreshold}
| *No description.* |
+| addFreeStorageSpaceAlarm
| {[ key: string ]: MinUsageCountThreshold}
| *No description.* |
+| addMaxConnectionCountAlarm
| {[ key: string ]: HighConnectionCountThreshold}
| *No description.* |
+| addMinConnectionCountAlarm
| {[ key: string ]: LowConnectionCountThreshold}
| *No description.* |
+
+---
+
+##### `alarmFriendlyName`Optional
+
+```typescript
+public readonly alarmFriendlyName: string;
+```
+
+- *Type:* string
+- *Default:* derives name from the construct itself
+
+Plain name, used in naming alarms.
+
+This unique among other resources, and respect the AWS CDK restriction posed on alarm names.
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+---
+
+##### `humanReadableName`Optional
+
+```typescript
+public readonly humanReadableName: string;
+```
+
+- *Type:* string
+- *Default:* use alarmFriendlyName
+
+Human-readable name is a freeform string, used as a caption or description.
+
+There are no limitations on what it can be.
+
+---
+
+##### `localAlarmNamePrefixOverride`Optional
+
+```typescript
+public readonly localAlarmNamePrefixOverride: string;
+```
+
+- *Type:* string
+
+If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value.
+
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+> [AlarmNamingStrategy for more details on alarm name prefixes](AlarmNamingStrategy for more details on alarm name prefixes)
+
+---
+
+##### `addToAlarmDashboard`Optional
+
+```typescript
+public readonly addToAlarmDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to alarm dashboard.
+
+---
+
+##### `addToDetailDashboard`Optional
+
+```typescript
+public readonly addToDetailDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to detailed dashboard.
+
+---
+
+##### `addToSummaryDashboard`Optional
+
+```typescript
+public readonly addToSummaryDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to summary dashboard.
+
+---
+
+##### `useCreatedAlarms`Optional
+
+```typescript
+public readonly useCreatedAlarms: IAlarmConsumer;
+```
+
+- *Type:* IAlarmConsumer
+
+Calls provided function to process all alarms created.
+
+---
+
+##### `addCpuUsageAlarm`Optional
+
+```typescript
+public readonly addCpuUsageAlarm: {[ key: string ]: UsageThreshold};
+```
+
+- *Type:* {[ key: string ]: UsageThreshold}
+
+---
+
+##### `addFreeStorageSpaceAlarm`Optional
+
+```typescript
+public readonly addFreeStorageSpaceAlarm: {[ key: string ]: MinUsageCountThreshold};
+```
+
+- *Type:* {[ key: string ]: MinUsageCountThreshold}
+
+---
+
+##### `addMaxConnectionCountAlarm`Optional
+
+```typescript
+public readonly addMaxConnectionCountAlarm: {[ key: string ]: HighConnectionCountThreshold};
+```
+
+- *Type:* {[ key: string ]: HighConnectionCountThreshold}
+
+---
+
+##### `addMinConnectionCountAlarm`Optional
+
+```typescript
+public readonly addMinConnectionCountAlarm: {[ key: string ]: LowConnectionCountThreshold};
+```
+
+- *Type:* {[ key: string ]: LowConnectionCountThreshold}
+
+---
+
+### RdsInstanceMonitoringProps
+
+#### Initializer
+
+```typescript
+import { RdsInstanceMonitoringProps } from 'cdk-monitoring-constructs'
+
+const rdsInstanceMonitoringProps: RdsInstanceMonitoringProps = { ... }
+```
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| instance
| aws-cdk-lib.aws_rds.IDatabaseInstance
| database instance. |
+| alarmFriendlyName
| string
| Plain name, used in naming alarms. |
+| humanReadableName
| string
| Human-readable name is a freeform string, used as a caption or description. |
+| localAlarmNamePrefixOverride
| string
| If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value. |
+| addToAlarmDashboard
| boolean
| Flag indicating if the widgets should be added to alarm dashboard. |
+| 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. |
+| addCpuUsageAlarm
| {[ key: string ]: UsageThreshold}
| *No description.* |
+| addFreeStorageSpaceAlarm
| {[ key: string ]: MinUsageCountThreshold}
| *No description.* |
+| addMaxConnectionCountAlarm
| {[ key: string ]: HighConnectionCountThreshold}
| *No description.* |
+| addMinConnectionCountAlarm
| {[ key: string ]: LowConnectionCountThreshold}
| *No description.* |
+
+---
+
+##### `instance`Required
+
+```typescript
+public readonly instance: IDatabaseInstance;
+```
+
+- *Type:* aws-cdk-lib.aws_rds.IDatabaseInstance
+
+database instance.
+
+---
+
+##### `alarmFriendlyName`Optional
+
+```typescript
+public readonly alarmFriendlyName: string;
+```
+
+- *Type:* string
+- *Default:* derives name from the construct itself
+
+Plain name, used in naming alarms.
+
+This unique among other resources, and respect the AWS CDK restriction posed on alarm names.
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+---
+
+##### `humanReadableName`Optional
+
+```typescript
+public readonly humanReadableName: string;
+```
+
+- *Type:* string
+- *Default:* use alarmFriendlyName
+
+Human-readable name is a freeform string, used as a caption or description.
+
+There are no limitations on what it can be.
+
+---
+
+##### `localAlarmNamePrefixOverride`Optional
+
+```typescript
+public readonly localAlarmNamePrefixOverride: string;
+```
+
+- *Type:* string
+
+If this is defined, the local alarm name prefix used in naming alarms for the construct will be set to this value.
+
+The length must be 1 - 255 characters and although the validation rules are undocumented, we recommend using ASCII and hyphens.
+
+> [AlarmNamingStrategy for more details on alarm name prefixes](AlarmNamingStrategy for more details on alarm name prefixes)
+
+---
+
+##### `addToAlarmDashboard`Optional
+
+```typescript
+public readonly addToAlarmDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to alarm dashboard.
+
+---
+
+##### `addToDetailDashboard`Optional
+
+```typescript
+public readonly addToDetailDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to detailed dashboard.
+
+---
+
+##### `addToSummaryDashboard`Optional
+
+```typescript
+public readonly addToSummaryDashboard: boolean;
+```
+
+- *Type:* boolean
+- *Default:* true
+
+Flag indicating if the widgets should be added to summary dashboard.
+
+---
+
+##### `useCreatedAlarms`Optional
+
+```typescript
+public readonly useCreatedAlarms: IAlarmConsumer;
+```
+
+- *Type:* IAlarmConsumer
+
+Calls provided function to process all alarms created.
+
+---
+
+##### `addCpuUsageAlarm`Optional
+
+```typescript
+public readonly addCpuUsageAlarm: {[ key: string ]: UsageThreshold};
+```
+
+- *Type:* {[ key: string ]: UsageThreshold}
+
+---
+
+##### `addFreeStorageSpaceAlarm`Optional
+
+```typescript
+public readonly addFreeStorageSpaceAlarm: {[ key: string ]: MinUsageCountThreshold};
+```
+
+- *Type:* {[ key: string ]: MinUsageCountThreshold}
+
+---
+
+##### `addMaxConnectionCountAlarm`Optional
+
+```typescript
+public readonly addMaxConnectionCountAlarm: {[ key: string ]: HighConnectionCountThreshold};
+```
+
+- *Type:* {[ key: string ]: HighConnectionCountThreshold}
+
+---
+
+##### `addMinConnectionCountAlarm`Optional
+
+```typescript
+public readonly addMinConnectionCountAlarm: {[ key: string ]: LowConnectionCountThreshold};
+```
+
+- *Type:* {[ key: string ]: LowConnectionCountThreshold}
+
+---
+
### RecordsFailedThreshold
#### Initializer
@@ -49741,6 +50153,7 @@ new AwsConsoleUrlFactory(props: AwsConsoleUrlFactoryProps)
| getLambdaFunctionUrl
| *No description.* |
| getOpenSearchClusterUrl
| *No description.* |
| getRdsClusterUrl
| *No description.* |
+| getRdsInstanceUrl
| *No description.* |
| getRedshiftClusterUrl
| *No description.* |
| getS3BucketUrl
| *No description.* |
| getSnsTopicUrl
| *No description.* |
@@ -49923,6 +50336,18 @@ public getRdsClusterUrl(clusterId: string): string
---
+##### `getRdsInstanceUrl`
+
+```typescript
+public getRdsInstanceUrl(instanceId: string): string
+```
+
+###### `instanceId`Required
+
+- *Type:* string
+
+---
+
##### `getRedshiftClusterUrl`
```typescript
@@ -64444,6 +64869,547 @@ public readonly url: string;
---
+### RdsInstanceMetricFactory
+
+#### Initializers
+
+```typescript
+import { RdsInstanceMetricFactory } from 'cdk-monitoring-constructs'
+
+new RdsInstanceMetricFactory(metricFactory: MetricFactory, props: RdsInstanceMetricFactoryProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| metricFactory
| MetricFactory
| *No description.* |
+| props
| RdsInstanceMetricFactoryProps
| *No description.* |
+
+---
+
+##### `metricFactory`Required
+
+- *Type:* MetricFactory
+
+---
+
+##### `props`Required
+
+- *Type:* RdsInstanceMetricFactoryProps
+
+---
+
+#### Methods
+
+| **Name** | **Description** |
+| --- | --- |
+| metricAverageCpuUsageInPercent
| *No description.* |
+| metricAverageFreeableMemory
| *No description.* |
+| metricMaxFreeStorageSpace
| *No description.* |
+| metricReadIops
| *No description.* |
+| metricReadLatencyInMillis
| *No description.* |
+| metricReadThroughput
| *No description.* |
+| metricTotalConnectionCount
| *No description.* |
+| metricWriteIops
| *No description.* |
+| metricWriteLatencyInMillis
| *No description.* |
+| metricWriteThroughput
| *No description.* |
+
+---
+
+##### `metricAverageCpuUsageInPercent`
+
+```typescript
+public metricAverageCpuUsageInPercent(): Metric | MathExpression
+```
+
+##### `metricAverageFreeableMemory`
+
+```typescript
+public metricAverageFreeableMemory(): Metric | MathExpression
+```
+
+##### `metricMaxFreeStorageSpace`
+
+```typescript
+public metricMaxFreeStorageSpace(): Metric | MathExpression
+```
+
+##### `metricReadIops`
+
+```typescript
+public metricReadIops(): Metric | MathExpression
+```
+
+##### `metricReadLatencyInMillis`
+
+```typescript
+public metricReadLatencyInMillis(latencyType: LatencyType): Metric | MathExpression
+```
+
+###### `latencyType`Required
+
+- *Type:* LatencyType
+
+---
+
+##### `metricReadThroughput`
+
+```typescript
+public metricReadThroughput(): Metric | MathExpression
+```
+
+##### `metricTotalConnectionCount`
+
+```typescript
+public metricTotalConnectionCount(): Metric | MathExpression
+```
+
+##### `metricWriteIops`
+
+```typescript
+public metricWriteIops(): Metric | MathExpression
+```
+
+##### `metricWriteLatencyInMillis`
+
+```typescript
+public metricWriteLatencyInMillis(latencyType: LatencyType): Metric | MathExpression
+```
+
+###### `latencyType`Required
+
+- *Type:* LatencyType
+
+---
+
+##### `metricWriteThroughput`
+
+```typescript
+public metricWriteThroughput(): Metric | MathExpression
+```
+
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| instance
| aws-cdk-lib.aws_rds.IDatabaseInstance
| *No description.* |
+| instanceIdentifier
| string
| *No description.* |
+
+---
+
+##### `instance`Required
+
+```typescript
+public readonly instance: IDatabaseInstance;
+```
+
+- *Type:* aws-cdk-lib.aws_rds.IDatabaseInstance
+
+---
+
+##### `instanceIdentifier`Required
+
+```typescript
+public readonly instanceIdentifier: string;
+```
+
+- *Type:* string
+
+---
+
+
+### RdsInstanceMonitoring
+
+#### Initializers
+
+```typescript
+import { RdsInstanceMonitoring } from 'cdk-monitoring-constructs'
+
+new RdsInstanceMonitoring(scope: MonitoringScope, props: RdsInstanceMonitoringProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| scope
| MonitoringScope
| *No description.* |
+| props
| RdsInstanceMonitoringProps
| *No description.* |
+
+---
+
+##### `scope`Required
+
+- *Type:* MonitoringScope
+
+---
+
+##### `props`Required
+
+- *Type:* RdsInstanceMonitoringProps
+
+---
+
+#### Methods
+
+| **Name** | **Description** |
+| --- | --- |
+| addAlarm
| Adds an alarm. |
+| alarmWidgets
| Returns widgets for all alarms. |
+| createAlarmFactory
| Creates a new alarm factory. |
+| createdAlarms
| Returns all the alarms created. |
+| createMetricFactory
| Creates a new metric factory. |
+| createWidgetFactory
| Creates a new widget factory. |
+| summaryWidgets
| Returns widgets to be placed on the summary dashboard. |
+| widgets
| Returns widgets to be placed on the main dashboard. |
+| widgetsForDashboard
| Returns widgets for the requested dashboard type. |
+| createConnectionsWidget
| *No description.* |
+| createCpuAndDiskUsageWidget
| *No description.* |
+| createLatencyWidget
| *No description.* |
+| createTitleWidget
| *No description.* |
+
+---
+
+##### `addAlarm`
+
+```typescript
+public addAlarm(alarm: AlarmWithAnnotation): void
+```
+
+Adds an alarm.
+
+###### `alarm`Required
+
+- *Type:* AlarmWithAnnotation
+
+alarm to add.
+
+---
+
+##### `alarmWidgets`
+
+```typescript
+public alarmWidgets(): IWidget[]
+```
+
+Returns widgets for all alarms.
+
+These can go to runbook or to service dashboard.
+
+##### `createAlarmFactory`
+
+```typescript
+public createAlarmFactory(alarmNamePrefix: string): AlarmFactory
+```
+
+Creates a new alarm factory.
+
+Alarms created will be named with the given prefix, unless a local name override is present.
+
+###### `alarmNamePrefix`Required
+
+- *Type:* string
+
+alarm name prefix.
+
+---
+
+##### `createdAlarms`
+
+```typescript
+public createdAlarms(): AlarmWithAnnotation[]
+```
+
+Returns all the alarms created.
+
+##### `createMetricFactory`
+
+```typescript
+public createMetricFactory(): MetricFactory
+```
+
+Creates a new metric factory.
+
+##### `createWidgetFactory`
+
+```typescript
+public createWidgetFactory(): IWidgetFactory
+```
+
+Creates a new widget factory.
+
+##### `summaryWidgets`
+
+```typescript
+public summaryWidgets(): IWidget[]
+```
+
+Returns widgets to be placed on the summary dashboard.
+
+##### `widgets`
+
+```typescript
+public widgets(): IWidget[]
+```
+
+Returns widgets to be placed on the main dashboard.
+
+##### `widgetsForDashboard`
+
+```typescript
+public widgetsForDashboard(name: string): IWidget[]
+```
+
+Returns widgets for the requested dashboard type.
+
+###### `name`Required
+
+- *Type:* string
+
+---
+
+##### `createConnectionsWidget`
+
+```typescript
+public createConnectionsWidget(width: number, height: number): GraphWidget
+```
+
+###### `width`Required
+
+- *Type:* number
+
+---
+
+###### `height`Required
+
+- *Type:* number
+
+---
+
+##### `createCpuAndDiskUsageWidget`
+
+```typescript
+public createCpuAndDiskUsageWidget(width: number, height: number): GraphWidget
+```
+
+###### `width`Required
+
+- *Type:* number
+
+---
+
+###### `height`Required
+
+- *Type:* number
+
+---
+
+##### `createLatencyWidget`
+
+```typescript
+public createLatencyWidget(width: number, height: number): GraphWidget
+```
+
+###### `width`Required
+
+- *Type:* number
+
+---
+
+###### `height`Required
+
+- *Type:* number
+
+---
+
+##### `createTitleWidget`
+
+```typescript
+public createTitleWidget(): MonitoringHeaderWidget
+```
+
+
+#### Properties
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| connectionAlarmFactory
| ConnectionAlarmFactory
| *No description.* |
+| connectionAnnotations
| aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[]
| *No description.* |
+| connectionsMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| cpuUsageMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| freeableMemoryMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| freeStorageSpaceMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| readIopsMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| readLatencyMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| readThroughputMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| title
| string
| *No description.* |
+| usageAlarmFactory
| UsageAlarmFactory
| *No description.* |
+| usageAnnotations
| aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[]
| *No description.* |
+| writeIopsMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| writeLatencyMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| writeThroughputMetric
| aws-cdk-lib.aws_cloudwatch.Metric \| aws-cdk-lib.aws_cloudwatch.MathExpression
| *No description.* |
+| url
| string
| *No description.* |
+
+---
+
+##### `connectionAlarmFactory`Required
+
+```typescript
+public readonly connectionAlarmFactory: ConnectionAlarmFactory;
+```
+
+- *Type:* ConnectionAlarmFactory
+
+---
+
+##### `connectionAnnotations`Required
+
+```typescript
+public readonly connectionAnnotations: HorizontalAnnotation[];
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[]
+
+---
+
+##### `connectionsMetric`Required
+
+```typescript
+public readonly connectionsMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `cpuUsageMetric`Required
+
+```typescript
+public readonly cpuUsageMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `freeableMemoryMetric`Required
+
+```typescript
+public readonly freeableMemoryMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `freeStorageSpaceMetric`Required
+
+```typescript
+public readonly freeStorageSpaceMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `readIopsMetric`Required
+
+```typescript
+public readonly readIopsMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `readLatencyMetric`Required
+
+```typescript
+public readonly readLatencyMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `readThroughputMetric`Required
+
+```typescript
+public readonly readThroughputMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `title`Required
+
+```typescript
+public readonly title: string;
+```
+
+- *Type:* string
+
+---
+
+##### `usageAlarmFactory`Required
+
+```typescript
+public readonly usageAlarmFactory: UsageAlarmFactory;
+```
+
+- *Type:* UsageAlarmFactory
+
+---
+
+##### `usageAnnotations`Required
+
+```typescript
+public readonly usageAnnotations: HorizontalAnnotation[];
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.HorizontalAnnotation[]
+
+---
+
+##### `writeIopsMetric`Required
+
+```typescript
+public readonly writeIopsMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `writeLatencyMetric`Required
+
+```typescript
+public readonly writeLatencyMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `writeThroughputMetric`Required
+
+```typescript
+public readonly writeThroughputMetric: Metric | MathExpression;
+```
+
+- *Type:* aws-cdk-lib.aws_cloudwatch.Metric | aws-cdk-lib.aws_cloudwatch.MathExpression
+
+---
+
+##### `url`Optional
+
+```typescript
+public readonly url: string;
+```
+
+- *Type:* string
+
+---
+
+
### RedshiftClusterMetricFactory
#### Initializers
@@ -71459,7 +72425,7 @@ Dashboard placement override props.
### IDashboardSegment
-- *Implemented By:* ApiGatewayMonitoring, ApiGatewayV2HttpApiMonitoring, AppSyncMonitoring, AuroraClusterMonitoring, AutoScalingGroupMonitoring, BillingMonitoring, CertificateManagerMonitoring, CloudFrontDistributionMonitoring, CodeBuildProjectMonitoring, CustomMonitoring, DocumentDbMonitoring, DynamoTableGlobalSecondaryIndexMonitoring, DynamoTableMonitoring, EC2Monitoring, Ec2ServiceMonitoring, ElastiCacheClusterMonitoring, FargateServiceMonitoring, FluentBitMonitoring, GlueJobMonitoring, KinesisDataAnalyticsMonitoring, KinesisDataStreamMonitoring, KinesisFirehoseMonitoring, LambdaFunctionMonitoring, LogMonitoring, Monitoring, NetworkLoadBalancerMonitoring, OpenSearchClusterMonitoring, RdsClusterMonitoring, RedshiftClusterMonitoring, S3BucketMonitoring, SecretsManagerMonitoring, SecretsManagerSecretMonitoring, SingleWidgetDashboardSegment, SnsTopicMonitoring, SqsQueueMonitoring, SqsQueueMonitoringWithDlq, StepFunctionActivityMonitoring, StepFunctionLambdaIntegrationMonitoring, StepFunctionMonitoring, StepFunctionServiceIntegrationMonitoring, SyntheticsCanaryMonitoring, WafV2Monitoring, IDashboardSegment
+- *Implemented By:* ApiGatewayMonitoring, ApiGatewayV2HttpApiMonitoring, AppSyncMonitoring, AuroraClusterMonitoring, AutoScalingGroupMonitoring, BillingMonitoring, CertificateManagerMonitoring, CloudFrontDistributionMonitoring, CodeBuildProjectMonitoring, CustomMonitoring, DocumentDbMonitoring, DynamoTableGlobalSecondaryIndexMonitoring, DynamoTableMonitoring, EC2Monitoring, Ec2ServiceMonitoring, ElastiCacheClusterMonitoring, FargateServiceMonitoring, FluentBitMonitoring, GlueJobMonitoring, KinesisDataAnalyticsMonitoring, KinesisDataStreamMonitoring, KinesisFirehoseMonitoring, LambdaFunctionMonitoring, LogMonitoring, Monitoring, NetworkLoadBalancerMonitoring, OpenSearchClusterMonitoring, RdsClusterMonitoring, RdsInstanceMonitoring, RedshiftClusterMonitoring, S3BucketMonitoring, SecretsManagerMonitoring, SecretsManagerSecretMonitoring, SingleWidgetDashboardSegment, SnsTopicMonitoring, SqsQueueMonitoring, SqsQueueMonitoringWithDlq, StepFunctionActivityMonitoring, StepFunctionLambdaIntegrationMonitoring, StepFunctionMonitoring, StepFunctionServiceIntegrationMonitoring, SyntheticsCanaryMonitoring, WafV2Monitoring, IDashboardSegment
#### Methods
@@ -71550,7 +72516,7 @@ Gets the dashboard for the requested dashboard type.
### IDynamicDashboardSegment
-- *Implemented By:* ApiGatewayMonitoring, ApiGatewayV2HttpApiMonitoring, AppSyncMonitoring, AuroraClusterMonitoring, AutoScalingGroupMonitoring, BillingMonitoring, CertificateManagerMonitoring, CloudFrontDistributionMonitoring, CodeBuildProjectMonitoring, CustomMonitoring, DocumentDbMonitoring, DynamoTableGlobalSecondaryIndexMonitoring, DynamoTableMonitoring, EC2Monitoring, Ec2ServiceMonitoring, ElastiCacheClusterMonitoring, FargateServiceMonitoring, FluentBitMonitoring, GlueJobMonitoring, KinesisDataAnalyticsMonitoring, KinesisDataStreamMonitoring, KinesisFirehoseMonitoring, LambdaFunctionMonitoring, LogMonitoring, Monitoring, NetworkLoadBalancerMonitoring, OpenSearchClusterMonitoring, RdsClusterMonitoring, RedshiftClusterMonitoring, S3BucketMonitoring, SecretsManagerMonitoring, SecretsManagerSecretMonitoring, SingleWidgetDashboardSegment, SnsTopicMonitoring, SqsQueueMonitoring, SqsQueueMonitoringWithDlq, StaticSegmentDynamicAdapter, StepFunctionActivityMonitoring, StepFunctionLambdaIntegrationMonitoring, StepFunctionMonitoring, StepFunctionServiceIntegrationMonitoring, SyntheticsCanaryMonitoring, WafV2Monitoring, IDynamicDashboardSegment
+- *Implemented By:* ApiGatewayMonitoring, ApiGatewayV2HttpApiMonitoring, AppSyncMonitoring, AuroraClusterMonitoring, AutoScalingGroupMonitoring, BillingMonitoring, CertificateManagerMonitoring, CloudFrontDistributionMonitoring, CodeBuildProjectMonitoring, CustomMonitoring, DocumentDbMonitoring, DynamoTableGlobalSecondaryIndexMonitoring, DynamoTableMonitoring, EC2Monitoring, Ec2ServiceMonitoring, ElastiCacheClusterMonitoring, FargateServiceMonitoring, FluentBitMonitoring, GlueJobMonitoring, KinesisDataAnalyticsMonitoring, KinesisDataStreamMonitoring, KinesisFirehoseMonitoring, LambdaFunctionMonitoring, LogMonitoring, Monitoring, NetworkLoadBalancerMonitoring, OpenSearchClusterMonitoring, RdsClusterMonitoring, RdsInstanceMonitoring, RedshiftClusterMonitoring, S3BucketMonitoring, SecretsManagerMonitoring, SecretsManagerSecretMonitoring, SingleWidgetDashboardSegment, SnsTopicMonitoring, SqsQueueMonitoring, SqsQueueMonitoringWithDlq, StaticSegmentDynamicAdapter, StepFunctionActivityMonitoring, StepFunctionLambdaIntegrationMonitoring, StepFunctionMonitoring, StepFunctionServiceIntegrationMonitoring, SyntheticsCanaryMonitoring, WafV2Monitoring, IDynamicDashboardSegment
#### Methods
diff --git a/README.md b/README.md
index 706da8b2..c2040ff9 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,7 @@ You can browse the documentation at https://constructs.dev/packages/cdk-monitori
| AWS Load Balancing (`.monitorNetworkLoadBalancer()`, `.monitorFargateApplicationLoadBalancer()`, `.monitorFargateNetworkLoadBalancer()`, `.monitorEc2ApplicationLoadBalancer()`, `.monitorEc2NetworkLoadBalancer()`) | System resources and task health | Unhealthy task count, running tasks count, (for Fargate/Ec2 apps) CPU/memory usage | Use for FargateService or Ec2Service backed by a NetworkLoadBalancer or ApplicationLoadBalancer |
| AWS OpenSearch/Elasticsearch (`.monitorOpenSearchCluster()`, `.monitorElasticsearchCluster()`) | Indexing and search latency, disk/memory/CPU usage | Indexing and search latency, disk/memory/CPU usage, cluster status, KMS keys | |
| AWS RDS (`.monitorRdsCluster()`) | Query duration, connections, latency, disk/CPU usage | Connections, disk and CPU usage | |
+| AWS RDS (`.monitorRdsInstance()`) | Query duration, connections, latency, disk/CPU usage | Connections, disk and CPU usage | |
| AWS Redshift (`.monitorRedshiftCluster()`) | Query duration, connections, latency, disk/CPU usage | Query duration, connections, disk and CPU usage | |
| AWS S3 Bucket (`.monitorS3Bucket()`) | Bucket size and number of objects | | |
| AWS SecretsManager (`.monitorSecretsManager()`) | Max secret count, min secret sount, secret count change | Min/max secret count or change in secret count | |
diff --git a/lib/common/url/AwsConsoleUrlFactory.ts b/lib/common/url/AwsConsoleUrlFactory.ts
index 2321b9e4..bf9d825b 100644
--- a/lib/common/url/AwsConsoleUrlFactory.ts
+++ b/lib/common/url/AwsConsoleUrlFactory.ts
@@ -119,6 +119,12 @@ export class AwsConsoleUrlFactory {
return this.getAwsConsoleUrl(destinationUrl);
}
+ getRdsInstanceUrl(instanceId: string): string | undefined {
+ const region = this.awsAccountRegion;
+ const destinationUrl = `https://${region}.console.aws.amazon.com/rds/home?region=${region}#database:id=${instanceId};is-cluster=false;tab=monitoring`;
+ return this.getAwsConsoleUrl(destinationUrl);
+ }
+
getRedshiftClusterUrl(clusterId: string): string | undefined {
const region = this.awsAccountRegion;
const destinationUrl = `https://${region}.console.aws.amazon.com/redshiftv2/home?region=${region}#cluster-details?cluster=${clusterId}`;
diff --git a/lib/facade/IMonitoringAspect.ts b/lib/facade/IMonitoringAspect.ts
index b30c1dd9..ceefe8b1 100644
--- a/lib/facade/IMonitoringAspect.ts
+++ b/lib/facade/IMonitoringAspect.ts
@@ -19,6 +19,7 @@ import {
LambdaFunctionMonitoringOptions,
OpenSearchClusterMonitoringOptions,
RdsClusterMonitoringOptions,
+ RdsInstanceMonitoringOptions,
RedshiftClusterMonitoringOptions,
S3BucketMonitoringOptions,
SecretsManagerSecretMonitoringOptions,
@@ -63,7 +64,12 @@ export interface MonitoringAspectProps {
readonly kinesisFirehose?: MonitoringAspectType;
readonly lambda?: MonitoringAspectType;
readonly openSearch?: MonitoringAspectType;
+ /**
+ * @deprecated Use rdsCluster instead.
+ */
readonly rds?: MonitoringAspectType;
+ readonly rdsCluster?: MonitoringAspectType;
+ readonly rdsInstance?: MonitoringAspectType;
readonly redshift?: MonitoringAspectType;
readonly s3?: MonitoringAspectType;
readonly secretsManager?: MonitoringAspectType;
diff --git a/lib/facade/MonitoringAspect.ts b/lib/facade/MonitoringAspect.ts
index 49c712e7..da7e08e4 100644
--- a/lib/facade/MonitoringAspect.ts
+++ b/lib/facade/MonitoringAspect.ts
@@ -64,7 +64,8 @@ export class MonitoringAspect implements IAspect {
this.monitorKinesisFirehose(node);
this.monitorLambda(node);
this.monitorOpenSearch(node);
- this.monitorRds(node);
+ this.monitorRdsCluster(node);
+ this.monitorRdsInstance(node);
this.monitorRedshift(node);
this.monitorS3(node);
this.monitorSecretsManager(node);
@@ -312,8 +313,10 @@ export class MonitoringAspect implements IAspect {
}
}
- private monitorRds(node: IConstruct) {
- const [isEnabled, props] = this.getMonitoringDetails(this.props.rds);
+ private monitorRdsCluster(node: IConstruct) {
+ const [isEnabled, props] = this.getMonitoringDetails(
+ this.props.rdsCluster ?? this.props.rds
+ );
if (isEnabled && node instanceof rds.DatabaseCluster) {
this.monitoringFacade.monitorRdsCluster({
cluster: node,
@@ -323,6 +326,19 @@ export class MonitoringAspect implements IAspect {
}
}
+ private monitorRdsInstance(node: IConstruct) {
+ const [isEnabled, props] = this.getMonitoringDetails(
+ this.props.rdsInstance
+ );
+ if (isEnabled && node instanceof rds.DatabaseInstance) {
+ this.monitoringFacade.monitorRdsInstance({
+ instance: node,
+ alarmFriendlyName: node.node.path,
+ ...props,
+ });
+ }
+ }
+
private monitorRedshift(node: IConstruct) {
const [isEnabled, props] = this.getMonitoringDetails(this.props.redshift);
if (isEnabled && node instanceof redshift.Cluster) {
diff --git a/lib/facade/MonitoringFacade.ts b/lib/facade/MonitoringFacade.ts
index 11d066bc..9f50c697 100644
--- a/lib/facade/MonitoringFacade.ts
+++ b/lib/facade/MonitoringFacade.ts
@@ -94,6 +94,8 @@ import {
QueueProcessingFargateServiceMonitoringProps,
RdsClusterMonitoring,
RdsClusterMonitoringProps,
+ RdsInstanceMonitoring,
+ RdsInstanceMonitoringProps,
RedshiftClusterMonitoring,
RedshiftClusterMonitoringProps,
S3BucketMonitoring,
@@ -681,6 +683,12 @@ export class MonitoringFacade extends MonitoringScope {
return this;
}
+ monitorRdsInstance(props: RdsInstanceMonitoringProps): this {
+ const segment = new RdsInstanceMonitoring(this, props);
+ this.addSegment(segment, props);
+ return this;
+ }
+
monitorRedshiftCluster(props: RedshiftClusterMonitoringProps): this {
const segment = new RedshiftClusterMonitoring(this, props);
this.addSegment(segment, props);
diff --git a/lib/monitoring/aws-rds/RdsInstanceMetricFactory.ts b/lib/monitoring/aws-rds/RdsInstanceMetricFactory.ts
new file mode 100644
index 00000000..a6b13f0f
--- /dev/null
+++ b/lib/monitoring/aws-rds/RdsInstanceMetricFactory.ts
@@ -0,0 +1,141 @@
+import { DimensionsMap } from "aws-cdk-lib/aws-cloudwatch";
+import { IDatabaseInstance } from "aws-cdk-lib/aws-rds";
+
+import {
+ LatencyType,
+ MetricFactory,
+ MetricStatistic,
+ getLatencyTypeLabel,
+ getLatencyTypeStatistic,
+} from "../../common";
+
+const RdsNamespace = "AWS/RDS";
+
+export interface RdsInstanceMetricFactoryProps {
+ /**
+ * database instance
+ */
+ readonly instance: IDatabaseInstance;
+}
+
+export class RdsInstanceMetricFactory {
+ readonly instanceIdentifier: string;
+ readonly instance: IDatabaseInstance;
+ protected readonly metricFactory: MetricFactory;
+ protected readonly dimensionsMap: DimensionsMap;
+
+ constructor(
+ metricFactory: MetricFactory,
+ props: RdsInstanceMetricFactoryProps
+ ) {
+ this.metricFactory = metricFactory;
+ this.instance = props.instance;
+ this.instanceIdentifier = props.instance.instanceIdentifier;
+ this.dimensionsMap = {
+ DBInstanceIdentifier: this.instanceIdentifier,
+ };
+ }
+
+ metricTotalConnectionCount() {
+ return this.metricFactory.adaptMetric(
+ this.instance.metricDatabaseConnections({
+ statistic: MetricStatistic.SUM,
+ label: "Connections: Sum",
+ })
+ );
+ }
+
+ metricAverageCpuUsageInPercent() {
+ return this.metricFactory.adaptMetric(
+ this.instance.metricCPUUtilization({
+ statistic: MetricStatistic.AVERAGE,
+ label: "CPU Usage",
+ })
+ );
+ }
+
+ metricMaxFreeStorageSpace() {
+ return this.metricFactory.adaptMetric(
+ this.instance.metricFreeStorageSpace({
+ statistic: MetricStatistic.MAX,
+ label: "FreeStorageSpace: MAX",
+ })
+ );
+ }
+
+ metricAverageFreeableMemory() {
+ return this.metricFactory.adaptMetric(
+ this.instance.metricFreeableMemory({
+ statistic: MetricStatistic.AVERAGE,
+ label: "FreeStorageSpace: Average",
+ })
+ );
+ }
+
+ metricReadLatencyInMillis(latencyType: LatencyType) {
+ const label = "ReadLatency " + getLatencyTypeLabel(latencyType);
+ return this.metric(
+ "ReadLatency",
+ getLatencyTypeStatistic(latencyType),
+ label
+ );
+ }
+
+ metricReadThroughput() {
+ return this.metric(
+ "ReadThroughput",
+ MetricStatistic.AVERAGE,
+ "ReadThroughput: Average"
+ );
+ }
+
+ metricReadIops() {
+ return this.metricFactory.adaptMetric(
+ this.instance.metricReadIOPS({
+ statistic: MetricStatistic.AVERAGE,
+ label: "ReadIOPS: Average",
+ })
+ );
+ }
+
+ metricWriteLatencyInMillis(latencyType: LatencyType) {
+ const label = "WriteLatency " + getLatencyTypeLabel(latencyType);
+ return this.metric(
+ "WriteLatency",
+ getLatencyTypeStatistic(latencyType),
+ label
+ );
+ }
+
+ metricWriteThroughput() {
+ return this.metric(
+ "WriteThroughput",
+ MetricStatistic.AVERAGE,
+ "WriteThroughput: Average"
+ );
+ }
+
+ metricWriteIops() {
+ return this.metricFactory.adaptMetric(
+ this.instance.metricWriteIOPS({
+ statistic: MetricStatistic.AVERAGE,
+ label: "WriteIOPS: Average",
+ })
+ );
+ }
+
+ private metric(
+ metricName: string,
+ statistic: MetricStatistic,
+ label: string
+ ) {
+ return this.metricFactory.createMetric(
+ metricName,
+ statistic,
+ label,
+ this.dimensionsMap,
+ undefined,
+ RdsNamespace
+ );
+ }
+}
diff --git a/lib/monitoring/aws-rds/RdsInstanceMonitoring.ts b/lib/monitoring/aws-rds/RdsInstanceMonitoring.ts
new file mode 100644
index 00000000..324cd789
--- /dev/null
+++ b/lib/monitoring/aws-rds/RdsInstanceMonitoring.ts
@@ -0,0 +1,231 @@
+import {
+ GraphWidget,
+ HorizontalAnnotation,
+ IWidget,
+} from "aws-cdk-lib/aws-cloudwatch";
+
+import {
+ RdsInstanceMetricFactory,
+ RdsInstanceMetricFactoryProps,
+} from "./RdsInstanceMetricFactory";
+import {
+ BaseMonitoringProps,
+ ConnectionAlarmFactory,
+ CountAxisFromZero,
+ DefaultGraphWidgetHeight,
+ DefaultSummaryWidgetHeight,
+ HalfWidth,
+ HighConnectionCountThreshold,
+ LatencyType,
+ LowConnectionCountThreshold,
+ MetricWithAlarmSupport,
+ MinUsageCountThreshold,
+ Monitoring,
+ MonitoringScope,
+ PercentageAxisFromZeroToHundred,
+ QuarterWidth,
+ ThirdWidth,
+ TimeAxisMillisFromZero,
+ UsageAlarmFactory,
+ UsageThreshold,
+} from "../../common";
+import {
+ MonitoringHeaderWidget,
+ MonitoringNamingStrategy,
+} from "../../dashboard";
+
+export interface RdsInstanceMonitoringOptions extends BaseMonitoringProps {
+ readonly addFreeStorageSpaceAlarm?: Record;
+ readonly addCpuUsageAlarm?: Record;
+ readonly addMinConnectionCountAlarm?: Record<
+ string,
+ LowConnectionCountThreshold
+ >;
+ readonly addMaxConnectionCountAlarm?: Record<
+ string,
+ HighConnectionCountThreshold
+ >;
+}
+
+export interface RdsInstanceMonitoringProps
+ extends RdsInstanceMetricFactoryProps,
+ RdsInstanceMonitoringOptions {}
+
+export class RdsInstanceMonitoring extends Monitoring {
+ readonly title: string;
+ readonly url?: string;
+
+ readonly usageAlarmFactory: UsageAlarmFactory;
+ readonly connectionAlarmFactory: ConnectionAlarmFactory;
+ readonly usageAnnotations: HorizontalAnnotation[];
+ readonly connectionAnnotations: HorizontalAnnotation[];
+
+ readonly connectionsMetric: MetricWithAlarmSupport;
+ readonly freeStorageSpaceMetric: MetricWithAlarmSupport;
+ readonly freeableMemoryMetric: MetricWithAlarmSupport;
+ readonly cpuUsageMetric: MetricWithAlarmSupport;
+ readonly readLatencyMetric: MetricWithAlarmSupport;
+ readonly readThroughputMetric: MetricWithAlarmSupport;
+ readonly readIopsMetric: MetricWithAlarmSupport;
+ readonly writeLatencyMetric: MetricWithAlarmSupport;
+ readonly writeThroughputMetric: MetricWithAlarmSupport;
+ readonly writeIopsMetric: MetricWithAlarmSupport;
+
+ constructor(scope: MonitoringScope, props: RdsInstanceMonitoringProps) {
+ super(scope, props);
+
+ const metricFactory = new RdsInstanceMetricFactory(
+ scope.createMetricFactory(),
+ props
+ );
+ this.connectionsMetric = metricFactory.metricTotalConnectionCount();
+ this.freeStorageSpaceMetric = metricFactory.metricMaxFreeStorageSpace();
+ this.freeableMemoryMetric = metricFactory.metricAverageFreeableMemory();
+ this.cpuUsageMetric = metricFactory.metricAverageCpuUsageInPercent();
+ this.readLatencyMetric = metricFactory.metricReadLatencyInMillis(
+ LatencyType.P90
+ );
+ this.readThroughputMetric = metricFactory.metricReadThroughput();
+ this.readIopsMetric = metricFactory.metricReadIops();
+ this.writeLatencyMetric = metricFactory.metricWriteLatencyInMillis(
+ LatencyType.P90
+ );
+ this.writeThroughputMetric = metricFactory.metricWriteThroughput();
+ this.writeIopsMetric = metricFactory.metricWriteIops();
+
+ const namingStrategy = new MonitoringNamingStrategy({
+ ...props,
+ fallbackConstructName: metricFactory.instanceIdentifier,
+ namedConstruct: props.instance,
+ });
+ this.title = namingStrategy.resolveHumanReadableName();
+ this.url = scope
+ .createAwsConsoleUrlFactory()
+ .getRdsInstanceUrl(metricFactory.instanceIdentifier);
+ const alarmFactory = this.createAlarmFactory(
+ namingStrategy.resolveAlarmFriendlyName()
+ );
+ this.usageAlarmFactory = new UsageAlarmFactory(alarmFactory);
+ this.connectionAlarmFactory = new ConnectionAlarmFactory(alarmFactory);
+
+ this.usageAnnotations = [];
+ this.connectionAnnotations = [];
+
+ for (const disambiguator in props.addFreeStorageSpaceAlarm) {
+ const alarmProps = props.addFreeStorageSpaceAlarm[disambiguator];
+ const createdAlarm = this.usageAlarmFactory.addMinCountAlarm(
+ this.freeStorageSpaceMetric,
+ alarmProps,
+ disambiguator
+ );
+ this.usageAnnotations.push(createdAlarm.annotation);
+ this.addAlarm(createdAlarm);
+ }
+
+ for (const disambiguator in props.addCpuUsageAlarm) {
+ const alarmProps = props.addCpuUsageAlarm[disambiguator];
+ const createdAlarm = this.usageAlarmFactory.addMaxCpuUsagePercentAlarm(
+ this.cpuUsageMetric,
+ alarmProps,
+ disambiguator
+ );
+ this.usageAnnotations.push(createdAlarm.annotation);
+ this.addAlarm(createdAlarm);
+ }
+
+ for (const disambiguator in props.addMinConnectionCountAlarm) {
+ const alarmProps = props.addMinConnectionCountAlarm[disambiguator];
+ const createdAlarm =
+ this.connectionAlarmFactory.addMinConnectionCountAlarm(
+ this.connectionsMetric,
+ alarmProps,
+ disambiguator
+ );
+ this.connectionAnnotations.push(createdAlarm.annotation);
+ this.addAlarm(createdAlarm);
+ }
+
+ for (const disambiguator in props.addMaxConnectionCountAlarm) {
+ const alarmProps = props.addMaxConnectionCountAlarm[disambiguator];
+ const createdAlarm =
+ this.connectionAlarmFactory.addMaxConnectionCountAlarm(
+ this.connectionsMetric,
+ alarmProps,
+ disambiguator
+ );
+ this.connectionAnnotations.push(createdAlarm.annotation);
+ this.addAlarm(createdAlarm);
+ }
+
+ props.useCreatedAlarms?.consume(this.createdAlarms());
+ }
+
+ summaryWidgets(): IWidget[] {
+ return [
+ this.createTitleWidget(),
+ this.createCpuAndDiskUsageWidget(ThirdWidth, DefaultSummaryWidgetHeight),
+ this.createConnectionsWidget(ThirdWidth, DefaultSummaryWidgetHeight),
+ this.createLatencyWidget(ThirdWidth, DefaultSummaryWidgetHeight),
+ ];
+ }
+
+ widgets(): IWidget[] {
+ return [
+ this.createTitleWidget(),
+ this.createCpuAndDiskUsageWidget(QuarterWidth, DefaultGraphWidgetHeight),
+ this.createConnectionsWidget(QuarterWidth, DefaultGraphWidgetHeight),
+ this.createLatencyWidget(HalfWidth, DefaultGraphWidgetHeight),
+ ];
+ }
+
+ createTitleWidget() {
+ return new MonitoringHeaderWidget({
+ family: "RDS Instance",
+ title: this.title,
+ goToLinkUrl: this.url,
+ });
+ }
+
+ createCpuAndDiskUsageWidget(width: number, height: number) {
+ return new GraphWidget({
+ width,
+ height,
+ title: "CPU/Disk Usage",
+ left: [
+ this.cpuUsageMetric,
+ this.freeStorageSpaceMetric,
+ this.freeableMemoryMetric,
+ ],
+ leftYAxis: PercentageAxisFromZeroToHundred,
+ leftAnnotations: this.usageAnnotations,
+ });
+ }
+
+ createConnectionsWidget(width: number, height: number) {
+ return new GraphWidget({
+ width,
+ height,
+ title: "Connections",
+ left: [this.connectionsMetric],
+ leftYAxis: CountAxisFromZero,
+ leftAnnotations: this.connectionAnnotations,
+ });
+ }
+
+ createLatencyWidget(width: number, height: number) {
+ return new GraphWidget({
+ width,
+ height,
+ title: "Query Duration",
+ left: [
+ this.readLatencyMetric,
+ this.readThroughputMetric,
+ this.readIopsMetric,
+ this.writeLatencyMetric,
+ this.writeLatencyMetric,
+ this.writeIopsMetric,
+ ],
+ leftYAxis: TimeAxisMillisFromZero,
+ });
+ }
+}
diff --git a/lib/monitoring/aws-rds/index.ts b/lib/monitoring/aws-rds/index.ts
index 0a738d86..beaf9f5b 100644
--- a/lib/monitoring/aws-rds/index.ts
+++ b/lib/monitoring/aws-rds/index.ts
@@ -1,3 +1,5 @@
export * from "./AuroraClusterMonitoring";
export * from "./RdsClusterMetricFactory";
export * from "./RdsClusterMonitoring";
+export * from "./RdsInstanceMetricFactory";
+export * from "./RdsInstanceMonitoring";
diff --git a/test/monitoring/aws-rds/RdsInstanceMonitoring.test.ts b/test/monitoring/aws-rds/RdsInstanceMonitoring.test.ts
new file mode 100644
index 00000000..b8ace0dc
--- /dev/null
+++ b/test/monitoring/aws-rds/RdsInstanceMonitoring.test.ts
@@ -0,0 +1,73 @@
+import { Stack } from "aws-cdk-lib";
+import { Template } from "aws-cdk-lib/assertions";
+import { Vpc } from "aws-cdk-lib/aws-ec2";
+import { DatabaseInstance, DatabaseInstanceEngine } from "aws-cdk-lib/aws-rds";
+
+import { RdsInstanceMonitoring } from "../../../lib";
+import { addMonitoringDashboardsToStack } from "../../utils/SnapshotUtil";
+import { TestMonitoringScope } from "../TestMonitoringScope";
+
+function createRdsInstance() {
+ const stack = new Stack();
+ const vpc = new Vpc(stack, "Vpc");
+ const instance = new DatabaseInstance(stack, "DatabaseInstance", {
+ instanceIdentifier: "my-rds-instance",
+ engine: DatabaseInstanceEngine.MYSQL,
+ vpc: vpc,
+ });
+ return { instance, stack };
+}
+
+test.each([createRdsInstance])("snapshot test: no alarms - %#", (factory) => {
+ const { stack, instance } = factory();
+
+ const scope = new TestMonitoringScope(stack, "Scope");
+ const monitoring = new RdsInstanceMonitoring(scope, {
+ alarmFriendlyName: "DummyRdsInstance",
+ instance: instance,
+ });
+
+ addMonitoringDashboardsToStack(stack, monitoring);
+ expect(Template.fromStack(stack)).toMatchSnapshot();
+});
+
+test.each([createRdsInstance])("snapshot test: all alarms - %#", (factory) => {
+ const { stack, instance } = factory();
+
+ const scope = new TestMonitoringScope(stack, "Scope");
+
+ let numAlarmsCreated = 0;
+
+ const monitoring = new RdsInstanceMonitoring(scope, {
+ instance: instance,
+ addFreeStorageSpaceAlarm: {
+ Warning: {
+ minCount: 20,
+ },
+ },
+ addCpuUsageAlarm: {
+ Warning: {
+ maxUsagePercent: 70,
+ },
+ },
+ addMinConnectionCountAlarm: {
+ Warning: {
+ minConnectionCount: 1,
+ },
+ },
+ addMaxConnectionCountAlarm: {
+ Warning: {
+ maxConnectionCount: 100,
+ },
+ },
+ useCreatedAlarms: {
+ consume(alarms) {
+ numAlarmsCreated = alarms.length;
+ },
+ },
+ });
+
+ addMonitoringDashboardsToStack(stack, monitoring);
+ expect(numAlarmsCreated).toStrictEqual(4);
+ expect(Template.fromStack(stack)).toMatchSnapshot();
+});
diff --git a/test/monitoring/aws-rds/__snapshots__/RdsInstanceMonitoring.test.ts.snap b/test/monitoring/aws-rds/__snapshots__/RdsInstanceMonitoring.test.ts.snap
new file mode 100644
index 00000000..fc100eaf
--- /dev/null
+++ b/test/monitoring/aws-rds/__snapshots__/RdsInstanceMonitoring.test.ts.snap
@@ -0,0 +1,1560 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`snapshot test: all alarms - 0 1`] = `
+Object {
+ "Parameters": Object {
+ "BootstrapVersion": Object {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": Object {
+ "Alarm7103F465": Object {
+ "Properties": Object {
+ "DashboardBody": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{\\"widgets\\":[{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+ Object {
+ "Fn::GetAtt": Array [
+ "ScopeTestDatabaseInstanceMinUsageCountWarning32B7AE36",
+ "Arn",
+ ],
+ },
+ "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":6,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+ Object {
+ "Fn::GetAtt": Array [
+ "ScopeTestDatabaseInstanceCPUUsageWarningEF3425BC",
+ "Arn",
+ ],
+ },
+ "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":12,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+ Object {
+ "Fn::GetAtt": Array [
+ "ScopeTestDatabaseInstanceConnectionCountLowWarning07BAA2A4",
+ "Arn",
+ ],
+ },
+ "\\"]},\\"yAxis\\":{}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":4,\\"x\\":18,\\"y\\":0,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"annotations\\":{\\"alarms\\":[\\"",
+ Object {
+ "Fn::GetAtt": Array [
+ "ScopeTestDatabaseInstanceConnectionCountHighWarningD026F033",
+ "Arn",
+ ],
+ },
+ "\\"]},\\"yAxis\\":{}}}]}",
+ ],
+ ],
+ },
+ },
+ "Type": "AWS::CloudWatch::Dashboard",
+ },
+ "DatabaseInstance24D16791": Object {
+ "DeletionPolicy": "Snapshot",
+ "Properties": Object {
+ "AllocatedStorage": "100",
+ "CopyTagsToSnapshot": true,
+ "DBInstanceClass": "db.m5.large",
+ "DBInstanceIdentifier": "my-rds-instance",
+ "DBSubnetGroupName": Object {
+ "Ref": "DatabaseInstanceSubnetGroupA4FFF2A4",
+ },
+ "Engine": "mysql",
+ "MasterUserPassword": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{{resolve:secretsmanager:",
+ Object {
+ "Ref": "DatabaseInstanceSecret2C9E2EE4",
+ },
+ ":SecretString:password::}}",
+ ],
+ ],
+ },
+ "MasterUsername": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{{resolve:secretsmanager:",
+ Object {
+ "Ref": "DatabaseInstanceSecret2C9E2EE4",
+ },
+ ":SecretString:username::}}",
+ ],
+ ],
+ },
+ "StorageType": "gp2",
+ "VPCSecurityGroups": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "DatabaseInstanceSecurityGroup8BDF0112",
+ "GroupId",
+ ],
+ },
+ ],
+ },
+ "Type": "AWS::RDS::DBInstance",
+ "UpdateReplacePolicy": "Snapshot",
+ },
+ "DatabaseInstanceSecret2C9E2EE4": Object {
+ "DeletionPolicy": "Delete",
+ "Properties": Object {
+ "Description": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "Generated by the CDK for stack: ",
+ Object {
+ "Ref": "AWS::StackName",
+ },
+ ],
+ ],
+ },
+ "GenerateSecretString": Object {
+ "ExcludeCharacters": " %+~\`#$&*()|[]{}:;<>?!'/@\\"\\\\",
+ "GenerateStringKey": "password",
+ "PasswordLength": 30,
+ "SecretStringTemplate": "{\\"username\\":\\"admin\\"}",
+ },
+ },
+ "Type": "AWS::SecretsManager::Secret",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "DatabaseInstanceSecretAttachmentF5C7BAE8": Object {
+ "Properties": Object {
+ "SecretId": Object {
+ "Ref": "DatabaseInstanceSecret2C9E2EE4",
+ },
+ "TargetId": Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "TargetType": "AWS::RDS::DBInstance",
+ },
+ "Type": "AWS::SecretsManager::SecretTargetAttachment",
+ },
+ "DatabaseInstanceSecurityGroup8BDF0112": Object {
+ "Properties": Object {
+ "GroupDescription": "Security group for DatabaseInstance database",
+ "SecurityGroupEgress": Array [
+ Object {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "DatabaseInstanceSubnetGroupA4FFF2A4": Object {
+ "Properties": Object {
+ "DBSubnetGroupDescription": "Subnet group for DatabaseInstance database",
+ "SubnetIds": Array [
+ Object {
+ "Ref": "VpcPrivateSubnet1Subnet536B997A",
+ },
+ Object {
+ "Ref": "VpcPrivateSubnet2Subnet3788AAA1",
+ },
+ ],
+ },
+ "Type": "AWS::RDS::DBSubnetGroup",
+ },
+ "Resource": Object {
+ "Properties": Object {
+ "DashboardBody": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### RDS Instance **[DatabaseInstance](https://eu-west-1.console.aws.amazon.com/rds/home?region=eu-west-1#database:id=",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ ";is-cluster=false;tab=monitoring)**\\"}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Disk Usage\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"CPUUtilization\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"CPU Usage\\"}],[\\"AWS/RDS\\",\\"FreeStorageSpace\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: MAX\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/RDS\\",\\"FreeableMemory\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: Average\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"FreeStorageSpace: MAX < 20 for 3 datapoints within 15 minutes\\",\\"value\\":20,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPU Usage > 70 for 3 datapoints within 15 minutes\\",\\"value\\":70,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":6,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Connections\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"DatabaseConnections\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"Connections: Sum\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Connections: Sum < 1 for 3 datapoints within 15 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Connections: Sum > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":5,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Query Duration\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"ReadLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"ReadThroughput\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadThroughput: Average\\"}],[\\"AWS/RDS\\",\\"ReadIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadIOPS: Average\\"}],[\\"AWS/RDS\\",\\"WriteLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"WriteIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteIOPS: Average\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}}]}",
+ ],
+ ],
+ },
+ },
+ "Type": "AWS::CloudWatch::Dashboard",
+ },
+ "ScopeTestDatabaseInstanceCPUUsageWarningEF3425BC": Object {
+ "Properties": Object {
+ "ActionsEnabled": true,
+ "AlarmDescription": "The CPU usage is too high.",
+ "AlarmName": "Test-DatabaseInstance-CPU-Usage-Warning",
+ "ComparisonOperator": "GreaterThanThreshold",
+ "DatapointsToAlarm": 3,
+ "EvaluationPeriods": 3,
+ "Metrics": Array [
+ Object {
+ "Id": "m1",
+ "Label": "CPU Usage",
+ "MetricStat": Object {
+ "Metric": Object {
+ "Dimensions": Array [
+ Object {
+ "Name": "DBInstanceIdentifier",
+ "Value": Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ },
+ ],
+ "MetricName": "CPUUtilization",
+ "Namespace": "AWS/RDS",
+ },
+ "Period": 300,
+ "Stat": "Average",
+ },
+ "ReturnData": true,
+ },
+ ],
+ "Threshold": 70,
+ "TreatMissingData": "missing",
+ },
+ "Type": "AWS::CloudWatch::Alarm",
+ },
+ "ScopeTestDatabaseInstanceConnectionCountHighWarningD026F033": Object {
+ "Properties": Object {
+ "ActionsEnabled": true,
+ "AlarmDescription": "Number of connections is too high.",
+ "AlarmName": "Test-DatabaseInstance-Connection-Count-High-Warning",
+ "ComparisonOperator": "GreaterThanThreshold",
+ "DatapointsToAlarm": 3,
+ "EvaluationPeriods": 3,
+ "Metrics": Array [
+ Object {
+ "Id": "m1",
+ "Label": "Connections: Sum",
+ "MetricStat": Object {
+ "Metric": Object {
+ "Dimensions": Array [
+ Object {
+ "Name": "DBInstanceIdentifier",
+ "Value": Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ },
+ ],
+ "MetricName": "DatabaseConnections",
+ "Namespace": "AWS/RDS",
+ },
+ "Period": 300,
+ "Stat": "Sum",
+ },
+ "ReturnData": true,
+ },
+ ],
+ "Threshold": 100,
+ "TreatMissingData": "missing",
+ },
+ "Type": "AWS::CloudWatch::Alarm",
+ },
+ "ScopeTestDatabaseInstanceConnectionCountLowWarning07BAA2A4": Object {
+ "Properties": Object {
+ "ActionsEnabled": true,
+ "AlarmDescription": "Number of connections is too low.",
+ "AlarmName": "Test-DatabaseInstance-Connection-Count-Low-Warning",
+ "ComparisonOperator": "LessThanThreshold",
+ "DatapointsToAlarm": 3,
+ "EvaluationPeriods": 3,
+ "Metrics": Array [
+ Object {
+ "Id": "m1",
+ "Label": "Connections: Sum",
+ "MetricStat": Object {
+ "Metric": Object {
+ "Dimensions": Array [
+ Object {
+ "Name": "DBInstanceIdentifier",
+ "Value": Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ },
+ ],
+ "MetricName": "DatabaseConnections",
+ "Namespace": "AWS/RDS",
+ },
+ "Period": 300,
+ "Stat": "Sum",
+ },
+ "ReturnData": true,
+ },
+ ],
+ "Threshold": 1,
+ "TreatMissingData": "missing",
+ },
+ "Type": "AWS::CloudWatch::Alarm",
+ },
+ "ScopeTestDatabaseInstanceMinUsageCountWarning32B7AE36": Object {
+ "Properties": Object {
+ "ActionsEnabled": true,
+ "AlarmDescription": "The count is too low.",
+ "AlarmName": "Test-DatabaseInstance-Min-Usage-Count-Warning",
+ "ComparisonOperator": "LessThanThreshold",
+ "DatapointsToAlarm": 3,
+ "EvaluationPeriods": 3,
+ "Metrics": Array [
+ Object {
+ "Id": "m1",
+ "Label": "FreeStorageSpace: MAX",
+ "MetricStat": Object {
+ "Metric": Object {
+ "Dimensions": Array [
+ Object {
+ "Name": "DBInstanceIdentifier",
+ "Value": Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ },
+ ],
+ "MetricName": "FreeStorageSpace",
+ "Namespace": "AWS/RDS",
+ },
+ "Period": 300,
+ "Stat": "Maximum",
+ },
+ "ReturnData": true,
+ },
+ ],
+ "Threshold": 20,
+ "TreatMissingData": "missing",
+ },
+ "Type": "AWS::CloudWatch::Alarm",
+ },
+ "Summary68521F81": Object {
+ "Properties": Object {
+ "DashboardBody": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### RDS Instance **[DatabaseInstance](https://eu-west-1.console.aws.amazon.com/rds/home?region=eu-west-1#database:id=",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ ";is-cluster=false;tab=monitoring)**\\"}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Disk Usage\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"CPUUtilization\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"CPU Usage\\"}],[\\"AWS/RDS\\",\\"FreeStorageSpace\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: MAX\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/RDS\\",\\"FreeableMemory\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: Average\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"FreeStorageSpace: MAX < 20 for 3 datapoints within 15 minutes\\",\\"value\\":20,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"CPU Usage > 70 for 3 datapoints within 15 minutes\\",\\"value\\":70,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":8,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Connections\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"DatabaseConnections\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"Connections: Sum\\",\\"stat\\":\\"Sum\\"}]],\\"annotations\\":{\\"horizontal\\":[{\\"label\\":\\"Connections: Sum < 1 for 3 datapoints within 15 minutes\\",\\"value\\":1,\\"yAxis\\":\\"left\\"},{\\"label\\":\\"Connections: Sum > 100 for 3 datapoints within 15 minutes\\",\\"value\\":100,\\"yAxis\\":\\"left\\"}]},\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Query Duration\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"ReadLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"ReadThroughput\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadThroughput: Average\\"}],[\\"AWS/RDS\\",\\"ReadIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadIOPS: Average\\"}],[\\"AWS/RDS\\",\\"WriteLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"WriteIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteIOPS: Average\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}}]}",
+ ],
+ ],
+ },
+ },
+ "Type": "AWS::CloudWatch::Dashboard",
+ },
+ "Vpc8378EB38": Object {
+ "Properties": Object {
+ "CidrBlock": "10.0.0.0/16",
+ "EnableDnsHostnames": true,
+ "EnableDnsSupport": true,
+ "InstanceTenancy": "default",
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::VPC",
+ },
+ "VpcIGWD7BA715C": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::InternetGateway",
+ },
+ "VpcPrivateSubnet1DefaultRouteBE02A9ED": Object {
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "NatGatewayId": Object {
+ "Ref": "VpcPublicSubnet1NATGateway4D7517AA",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet1RouteTableB2C5B500",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPrivateSubnet1RouteTableAssociation70C59FA6": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet1RouteTableB2C5B500",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPrivateSubnet1Subnet536B997A",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPrivateSubnet1RouteTableB2C5B500": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPrivateSubnet1Subnet536B997A": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 0,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.128.0/18",
+ "MapPublicIpOnLaunch": false,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcPrivateSubnet2DefaultRoute060D2087": Object {
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "NatGatewayId": Object {
+ "Ref": "VpcPublicSubnet2NATGateway9182C01D",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet2RouteTableA678073B",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPrivateSubnet2RouteTableA678073B": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPrivateSubnet2RouteTableAssociationA89CAD56": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet2RouteTableA678073B",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPrivateSubnet2Subnet3788AAA1",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPrivateSubnet2Subnet3788AAA1": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 1,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.192.0/18",
+ "MapPublicIpOnLaunch": false,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcPublicSubnet1DefaultRoute3DA9E72A": Object {
+ "DependsOn": Array [
+ "VpcVPCGWBF912B6E",
+ ],
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "GatewayId": Object {
+ "Ref": "VpcIGWD7BA715C",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet1RouteTable6C95E38E",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPublicSubnet1EIPD7E02669": Object {
+ "Properties": Object {
+ "Domain": "vpc",
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::EIP",
+ },
+ "VpcPublicSubnet1NATGateway4D7517AA": Object {
+ "DependsOn": Array [
+ "VpcPublicSubnet1DefaultRoute3DA9E72A",
+ "VpcPublicSubnet1RouteTableAssociation97140677",
+ ],
+ "Properties": Object {
+ "AllocationId": Object {
+ "Fn::GetAtt": Array [
+ "VpcPublicSubnet1EIPD7E02669",
+ "AllocationId",
+ ],
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet1Subnet5C2D37C4",
+ },
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::NatGateway",
+ },
+ "VpcPublicSubnet1RouteTable6C95E38E": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPublicSubnet1RouteTableAssociation97140677": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet1RouteTable6C95E38E",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet1Subnet5C2D37C4",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPublicSubnet1Subnet5C2D37C4": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 0,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.0.0/18",
+ "MapPublicIpOnLaunch": true,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcPublicSubnet2DefaultRoute97F91067": Object {
+ "DependsOn": Array [
+ "VpcVPCGWBF912B6E",
+ ],
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "GatewayId": Object {
+ "Ref": "VpcIGWD7BA715C",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet2RouteTable94F7E489",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPublicSubnet2EIP3C605A87": Object {
+ "Properties": Object {
+ "Domain": "vpc",
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::EIP",
+ },
+ "VpcPublicSubnet2NATGateway9182C01D": Object {
+ "DependsOn": Array [
+ "VpcPublicSubnet2DefaultRoute97F91067",
+ "VpcPublicSubnet2RouteTableAssociationDD5762D8",
+ ],
+ "Properties": Object {
+ "AllocationId": Object {
+ "Fn::GetAtt": Array [
+ "VpcPublicSubnet2EIP3C605A87",
+ "AllocationId",
+ ],
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet2Subnet691E08A3",
+ },
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::NatGateway",
+ },
+ "VpcPublicSubnet2RouteTable94F7E489": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPublicSubnet2RouteTableAssociationDD5762D8": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet2RouteTable94F7E489",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet2Subnet691E08A3",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPublicSubnet2Subnet691E08A3": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 1,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.64.0/18",
+ "MapPublicIpOnLaunch": true,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcVPCGWBF912B6E": Object {
+ "Properties": Object {
+ "InternetGatewayId": Object {
+ "Ref": "VpcIGWD7BA715C",
+ },
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::VPCGatewayAttachment",
+ },
+ },
+ "Rules": Object {
+ "CheckBootstrapVersion": Object {
+ "Assertions": Array [
+ Object {
+ "Assert": Object {
+ "Fn::Not": Array [
+ Object {
+ "Fn::Contains": Array [
+ Array [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ Object {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;
+
+exports[`snapshot test: no alarms - 0 1`] = `
+Object {
+ "Parameters": Object {
+ "BootstrapVersion": Object {
+ "Default": "/cdk-bootstrap/hnb659fds/version",
+ "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]",
+ "Type": "AWS::SSM::Parameter::Value",
+ },
+ },
+ "Resources": Object {
+ "Alarm7103F465": Object {
+ "Properties": Object {
+ "DashboardBody": "{\\"widgets\\":[]}",
+ },
+ "Type": "AWS::CloudWatch::Dashboard",
+ },
+ "DatabaseInstance24D16791": Object {
+ "DeletionPolicy": "Snapshot",
+ "Properties": Object {
+ "AllocatedStorage": "100",
+ "CopyTagsToSnapshot": true,
+ "DBInstanceClass": "db.m5.large",
+ "DBInstanceIdentifier": "my-rds-instance",
+ "DBSubnetGroupName": Object {
+ "Ref": "DatabaseInstanceSubnetGroupA4FFF2A4",
+ },
+ "Engine": "mysql",
+ "MasterUserPassword": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{{resolve:secretsmanager:",
+ Object {
+ "Ref": "DatabaseInstanceSecret2C9E2EE4",
+ },
+ ":SecretString:password::}}",
+ ],
+ ],
+ },
+ "MasterUsername": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{{resolve:secretsmanager:",
+ Object {
+ "Ref": "DatabaseInstanceSecret2C9E2EE4",
+ },
+ ":SecretString:username::}}",
+ ],
+ ],
+ },
+ "StorageType": "gp2",
+ "VPCSecurityGroups": Array [
+ Object {
+ "Fn::GetAtt": Array [
+ "DatabaseInstanceSecurityGroup8BDF0112",
+ "GroupId",
+ ],
+ },
+ ],
+ },
+ "Type": "AWS::RDS::DBInstance",
+ "UpdateReplacePolicy": "Snapshot",
+ },
+ "DatabaseInstanceSecret2C9E2EE4": Object {
+ "DeletionPolicy": "Delete",
+ "Properties": Object {
+ "Description": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "Generated by the CDK for stack: ",
+ Object {
+ "Ref": "AWS::StackName",
+ },
+ ],
+ ],
+ },
+ "GenerateSecretString": Object {
+ "ExcludeCharacters": " %+~\`#$&*()|[]{}:;<>?!'/@\\"\\\\",
+ "GenerateStringKey": "password",
+ "PasswordLength": 30,
+ "SecretStringTemplate": "{\\"username\\":\\"admin\\"}",
+ },
+ },
+ "Type": "AWS::SecretsManager::Secret",
+ "UpdateReplacePolicy": "Delete",
+ },
+ "DatabaseInstanceSecretAttachmentF5C7BAE8": Object {
+ "Properties": Object {
+ "SecretId": Object {
+ "Ref": "DatabaseInstanceSecret2C9E2EE4",
+ },
+ "TargetId": Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "TargetType": "AWS::RDS::DBInstance",
+ },
+ "Type": "AWS::SecretsManager::SecretTargetAttachment",
+ },
+ "DatabaseInstanceSecurityGroup8BDF0112": Object {
+ "Properties": Object {
+ "GroupDescription": "Security group for DatabaseInstance database",
+ "SecurityGroupEgress": Array [
+ Object {
+ "CidrIp": "0.0.0.0/0",
+ "Description": "Allow all outbound traffic by default",
+ "IpProtocol": "-1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::SecurityGroup",
+ },
+ "DatabaseInstanceSubnetGroupA4FFF2A4": Object {
+ "Properties": Object {
+ "DBSubnetGroupDescription": "Subnet group for DatabaseInstance database",
+ "SubnetIds": Array [
+ Object {
+ "Ref": "VpcPrivateSubnet1Subnet536B997A",
+ },
+ Object {
+ "Ref": "VpcPrivateSubnet2Subnet3788AAA1",
+ },
+ ],
+ },
+ "Type": "AWS::RDS::DBSubnetGroup",
+ },
+ "Resource": Object {
+ "Properties": Object {
+ "DashboardBody": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### RDS Instance **[DatabaseInstance](https://eu-west-1.console.aws.amazon.com/rds/home?region=eu-west-1#database:id=",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ ";is-cluster=false;tab=monitoring)**\\"}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Disk Usage\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"CPUUtilization\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"CPU Usage\\"}],[\\"AWS/RDS\\",\\"FreeStorageSpace\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: MAX\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/RDS\\",\\"FreeableMemory\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: Average\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":6,\\"height\\":5,\\"x\\":6,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Connections\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"DatabaseConnections\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"Connections: Sum\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":12,\\"height\\":5,\\"x\\":12,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Query Duration\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"ReadLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"ReadThroughput\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadThroughput: Average\\"}],[\\"AWS/RDS\\",\\"ReadIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadIOPS: Average\\"}],[\\"AWS/RDS\\",\\"WriteLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"WriteIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteIOPS: Average\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}}]}",
+ ],
+ ],
+ },
+ },
+ "Type": "AWS::CloudWatch::Dashboard",
+ },
+ "Summary68521F81": Object {
+ "Properties": Object {
+ "DashboardBody": Object {
+ "Fn::Join": Array [
+ "",
+ Array [
+ "{\\"widgets\\":[{\\"type\\":\\"text\\",\\"width\\":24,\\"height\\":1,\\"x\\":0,\\"y\\":0,\\"properties\\":{\\"markdown\\":\\"### RDS Instance **[DatabaseInstance](https://eu-west-1.console.aws.amazon.com/rds/home?region=eu-west-1#database:id=",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ ";is-cluster=false;tab=monitoring)**\\"}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":0,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"CPU/Disk Usage\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"CPUUtilization\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"CPU Usage\\"}],[\\"AWS/RDS\\",\\"FreeStorageSpace\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: MAX\\",\\"stat\\":\\"Maximum\\"}],[\\"AWS/RDS\\",\\"FreeableMemory\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"FreeStorageSpace: Average\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"max\\":100,\\"label\\":\\"%\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":8,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Connections\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"DatabaseConnections\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"Connections: Sum\\",\\"stat\\":\\"Sum\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"Count\\",\\"showUnits\\":false}}}},{\\"type\\":\\"metric\\",\\"width\\":8,\\"height\\":6,\\"x\\":16,\\"y\\":1,\\"properties\\":{\\"view\\":\\"timeSeries\\",\\"title\\":\\"Query Duration\\",\\"region\\":\\"",
+ Object {
+ "Ref": "AWS::Region",
+ },
+ "\\",\\"metrics\\":[[\\"AWS/RDS\\",\\"ReadLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"ReadThroughput\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadThroughput: Average\\"}],[\\"AWS/RDS\\",\\"ReadIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"ReadIOPS: Average\\"}],[\\"AWS/RDS\\",\\"WriteLatency\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteLatency P90 (avg: \${AVG})\\",\\"stat\\":\\"p90\\"}],[\\"AWS/RDS\\",\\"WriteIOPS\\",\\"DBInstanceIdentifier\\",\\"",
+ Object {
+ "Ref": "DatabaseInstance24D16791",
+ },
+ "\\",{\\"label\\":\\"WriteIOPS: Average\\"}]],\\"yAxis\\":{\\"left\\":{\\"min\\":0,\\"label\\":\\"ms\\",\\"showUnits\\":false}}}}]}",
+ ],
+ ],
+ },
+ },
+ "Type": "AWS::CloudWatch::Dashboard",
+ },
+ "Vpc8378EB38": Object {
+ "Properties": Object {
+ "CidrBlock": "10.0.0.0/16",
+ "EnableDnsHostnames": true,
+ "EnableDnsSupport": true,
+ "InstanceTenancy": "default",
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::VPC",
+ },
+ "VpcIGWD7BA715C": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::InternetGateway",
+ },
+ "VpcPrivateSubnet1DefaultRouteBE02A9ED": Object {
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "NatGatewayId": Object {
+ "Ref": "VpcPublicSubnet1NATGateway4D7517AA",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet1RouteTableB2C5B500",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPrivateSubnet1RouteTableAssociation70C59FA6": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet1RouteTableB2C5B500",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPrivateSubnet1Subnet536B997A",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPrivateSubnet1RouteTableB2C5B500": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPrivateSubnet1Subnet536B997A": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 0,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.128.0/18",
+ "MapPublicIpOnLaunch": false,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcPrivateSubnet2DefaultRoute060D2087": Object {
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "NatGatewayId": Object {
+ "Ref": "VpcPublicSubnet2NATGateway9182C01D",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet2RouteTableA678073B",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPrivateSubnet2RouteTableA678073B": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPrivateSubnet2RouteTableAssociationA89CAD56": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPrivateSubnet2RouteTableA678073B",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPrivateSubnet2Subnet3788AAA1",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPrivateSubnet2Subnet3788AAA1": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 1,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.192.0/18",
+ "MapPublicIpOnLaunch": false,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Private",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PrivateSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcPublicSubnet1DefaultRoute3DA9E72A": Object {
+ "DependsOn": Array [
+ "VpcVPCGWBF912B6E",
+ ],
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "GatewayId": Object {
+ "Ref": "VpcIGWD7BA715C",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet1RouteTable6C95E38E",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPublicSubnet1EIPD7E02669": Object {
+ "Properties": Object {
+ "Domain": "vpc",
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::EIP",
+ },
+ "VpcPublicSubnet1NATGateway4D7517AA": Object {
+ "DependsOn": Array [
+ "VpcPublicSubnet1DefaultRoute3DA9E72A",
+ "VpcPublicSubnet1RouteTableAssociation97140677",
+ ],
+ "Properties": Object {
+ "AllocationId": Object {
+ "Fn::GetAtt": Array [
+ "VpcPublicSubnet1EIPD7E02669",
+ "AllocationId",
+ ],
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet1Subnet5C2D37C4",
+ },
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::NatGateway",
+ },
+ "VpcPublicSubnet1RouteTable6C95E38E": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPublicSubnet1RouteTableAssociation97140677": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet1RouteTable6C95E38E",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet1Subnet5C2D37C4",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPublicSubnet1Subnet5C2D37C4": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 0,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.0.0/18",
+ "MapPublicIpOnLaunch": true,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet1",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcPublicSubnet2DefaultRoute97F91067": Object {
+ "DependsOn": Array [
+ "VpcVPCGWBF912B6E",
+ ],
+ "Properties": Object {
+ "DestinationCidrBlock": "0.0.0.0/0",
+ "GatewayId": Object {
+ "Ref": "VpcIGWD7BA715C",
+ },
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet2RouteTable94F7E489",
+ },
+ },
+ "Type": "AWS::EC2::Route",
+ },
+ "VpcPublicSubnet2EIP3C605A87": Object {
+ "Properties": Object {
+ "Domain": "vpc",
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::EIP",
+ },
+ "VpcPublicSubnet2NATGateway9182C01D": Object {
+ "DependsOn": Array [
+ "VpcPublicSubnet2DefaultRoute97F91067",
+ "VpcPublicSubnet2RouteTableAssociationDD5762D8",
+ ],
+ "Properties": Object {
+ "AllocationId": Object {
+ "Fn::GetAtt": Array [
+ "VpcPublicSubnet2EIP3C605A87",
+ "AllocationId",
+ ],
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet2Subnet691E08A3",
+ },
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ },
+ "Type": "AWS::EC2::NatGateway",
+ },
+ "VpcPublicSubnet2RouteTable94F7E489": Object {
+ "Properties": Object {
+ "Tags": Array [
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::RouteTable",
+ },
+ "VpcPublicSubnet2RouteTableAssociationDD5762D8": Object {
+ "Properties": Object {
+ "RouteTableId": Object {
+ "Ref": "VpcPublicSubnet2RouteTable94F7E489",
+ },
+ "SubnetId": Object {
+ "Ref": "VpcPublicSubnet2Subnet691E08A3",
+ },
+ },
+ "Type": "AWS::EC2::SubnetRouteTableAssociation",
+ },
+ "VpcPublicSubnet2Subnet691E08A3": Object {
+ "Properties": Object {
+ "AvailabilityZone": Object {
+ "Fn::Select": Array [
+ 1,
+ Object {
+ "Fn::GetAZs": "",
+ },
+ ],
+ },
+ "CidrBlock": "10.0.64.0/18",
+ "MapPublicIpOnLaunch": true,
+ "Tags": Array [
+ Object {
+ "Key": "aws-cdk:subnet-name",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "aws-cdk:subnet-type",
+ "Value": "Public",
+ },
+ Object {
+ "Key": "Name",
+ "Value": "Default/Vpc/PublicSubnet2",
+ },
+ ],
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::Subnet",
+ },
+ "VpcVPCGWBF912B6E": Object {
+ "Properties": Object {
+ "InternetGatewayId": Object {
+ "Ref": "VpcIGWD7BA715C",
+ },
+ "VpcId": Object {
+ "Ref": "Vpc8378EB38",
+ },
+ },
+ "Type": "AWS::EC2::VPCGatewayAttachment",
+ },
+ },
+ "Rules": Object {
+ "CheckBootstrapVersion": Object {
+ "Assertions": Array [
+ Object {
+ "Assert": Object {
+ "Fn::Not": Array [
+ Object {
+ "Fn::Contains": Array [
+ Array [
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ ],
+ Object {
+ "Ref": "BootstrapVersion",
+ },
+ ],
+ },
+ ],
+ },
+ "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.",
+ },
+ ],
+ },
+ },
+}
+`;