Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(aws-apigateway-kinesisstreams): Update construct to match DESIGN_GUIDELINES.md #395

Merged
merged 4 commits into from
Sep 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ _Parameters_
|existingStreamObj?|[`kinesis.Stream`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kinesis.Stream.html)|Existing instance of Kinesis Stream, providing both this and `kinesisStreamProps` will cause an error.|
|kinesisStreamProps?|[`kinesis.StreamProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kinesis.StreamProps.html)|Optional user-provided props to override the default props for the Kinesis stream.|
|logGroupProps?|[`logs.LogGroupProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroupProps.html)|User provided props to override the default props for for the CloudWatchLogs LogGroup.|
|createCloudWatchAlarms|`boolean`|Whether to create recommended CloudWatch alarms for Kinesis Data Stream. Default value is set to `true`|

## Pattern Properties

Expand All @@ -69,6 +70,7 @@ _Parameters_
|apiGatewayCloudWatchRole|[`iam.Role`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-iam.Role.html)|Returns an instance of the iam.Role created by the construct for API Gateway for CloudWatch access.|
|apiGatewayLogGroup|[`logs.LogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroup.html)|Returns an instance of the LogGroup created by the construct for API Gateway access logging to CloudWatch.|
|kinesisStream|[`kinesis.Stream`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kinesis.Stream.html)|Returns an instance of the Kinesis stream created or used by the pattern.|
|cloudwatchAlarms?|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns an array of recommended CloudWatch Alarms created by the construct for Kinesis Data stream|

## Sample API Usage

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import * as defaults from '@aws-solutions-constructs/core';
// Note: To ensure CDKv2 compatibility, keep the import statement for Construct separate
import { Construct } from '@aws-cdk/core';
import * as logs from '@aws-cdk/aws-logs';
import * as cloudwatch from '@aws-cdk/aws-cloudwatch';

/**
* @summary The properties for the ApiGatewayToKinesisStreamsProps class.
Expand Down Expand Up @@ -81,6 +82,12 @@ export interface ApiGatewayToKinesisStreamsProps {
* @default - Default props are used
*/
readonly logGroupProps?: logs.LogGroupProps
/**
* Whether to create recommended CloudWatch alarms
*
* @default - Alarms are created
*/
readonly createCloudWatchAlarms?: boolean;
}

/**
Expand All @@ -92,6 +99,7 @@ export class ApiGatewayToKinesisStreams extends Construct {
public readonly apiGatewayCloudWatchRole: iam.Role;
public readonly apiGatewayLogGroup: logs.LogGroup;
public readonly kinesisStream: kinesis.Stream;
public readonly cloudwatchAlarms?: cloudwatch.Alarm[];

/**
* @summary Constructs a new instance of the ApiGatewayToKinesisStreams class.
Expand Down Expand Up @@ -154,6 +162,11 @@ export class ApiGatewayToKinesisStreams extends Construct {
requestValidator,
requestModel: { 'application/json': this.getPutRecordsModel(props.putRecordsRequestModel) }
});

if (props.createCloudWatchAlarms === undefined || props.createCloudWatchAlarms) {
// Deploy best practices CW Alarms for Kinesis Stream
this.cloudwatchAlarms = defaults.buildKinesisStreamCWAlarms(this);
}
}

private getPutRecordTemplate(putRecordTemplate?: string): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/aws-kinesis": "0.0.0",
"@aws-cdk/aws-logs": "0.0.0",
"@aws-cdk/aws-cloudwatch": "0.0.0",
"@aws-solutions-constructs/core": "0.0.0",
"constructs": "^3.2.0"
},
Expand Down Expand Up @@ -87,7 +88,8 @@
"@aws-cdk/aws-kinesis": "0.0.0",
"@aws-solutions-constructs/core": "0.0.0",
"constructs": "^3.2.0",
"@aws-cdk/aws-logs": "0.0.0"
"@aws-cdk/aws-logs": "0.0.0",
"@aws-cdk/aws-cloudwatch": "0.0.0"
},
"keywords": [
"aws",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ test('Test construct properties', () => {
expect(pattern.apiGatewayCloudWatchRole !== null);
expect(pattern.apiGatewayLogGroup !== null);
expect(pattern.kinesisStream !== null);
expect(pattern.cloudwatchAlarms !== null);
});

// --------------------------------------------------------------
Expand Down Expand Up @@ -80,24 +81,33 @@ test('Test deployment w/ overwritten properties', () => {
ShardCount: 1,
Name: 'my-stream'
});

// Test for Cloudwatch Alarms
expect(stack).toCountResources('AWS::CloudWatch::Alarm', 2);
});

// --------------------------------------------------------------
// Test deployment w/ existing stream
// Test deployment w/ existing stream without default cloudwatch alarms
// --------------------------------------------------------------
test('Test deployment w/ existing stream', () => {
const stack = new Stack();

new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', {
const construct = new ApiGatewayToKinesisStreams(stack, 'api-gateway-kinesis', {
apiGatewayProps: {},
existingStreamObj: new kinesis.Stream(stack, 'ExistingStream', {
shardCount: 5,
retentionPeriod: Duration.days(4)
})
}),
createCloudWatchAlarms: false
});

expect(stack).toHaveResource('AWS::Kinesis::Stream', {
ShardCount: 5,
RetentionPeriodHours: 96
});

expect(construct.cloudwatchAlarms == null);

// Since createCloudWatchAlars is set to false, no Alarm should exist
expect(stack).not.toHaveResource('AWS::CloudWatch::Alarm');
});
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,32 @@
]
}
},
"testapigatewaykinesisoverwriteKinesisStreamGetRecordsIteratorAgeAlarmAF0BEF52": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"EvaluationPeriods": 1,
"AlarmDescription": "Consumer Record Processing Falling Behind, there is risk for data loss due to record expiration.",
"MetricName": "GetRecords.IteratorAgeMilliseconds",
"Namespace": "AWS/Kinesis",
"Period": 300,
"Statistic": "Maximum",
"Threshold": 2592000
}
},
"testapigatewaykinesisoverwriteKinesisStreamReadProvisionedThroughputExceededAlarm5C0040FB": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanThreshold",
"EvaluationPeriods": 1,
"AlarmDescription": "Consumer Application is Reading at a Slower Rate Than Expected.",
"MetricName": "ReadProvisionedThroughputExceeded",
"Namespace": "AWS/Kinesis",
"Period": 300,
"Statistic": "Average",
"Threshold": 0
}
},
"KinesisStream46752A3E": {
"Type": "AWS::Kinesis::Stream",
"Properties": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,32 @@
]
}
},
"testapigatewaykinesisdefaultKinesisStreamGetRecordsIteratorAgeAlarm0638BB32": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"EvaluationPeriods": 1,
"AlarmDescription": "Consumer Record Processing Falling Behind, there is risk for data loss due to record expiration.",
"MetricName": "GetRecords.IteratorAgeMilliseconds",
"Namespace": "AWS/Kinesis",
"Period": 300,
"Statistic": "Maximum",
"Threshold": 2592000
}
},
"testapigatewaykinesisdefaultKinesisStreamReadProvisionedThroughputExceededAlarmE7251F6A": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanThreshold",
"EvaluationPeriods": 1,
"AlarmDescription": "Consumer Application is Reading at a Slower Rate Than Expected.",
"MetricName": "ReadProvisionedThroughputExceeded",
"Namespace": "AWS/Kinesis",
"Period": 300,
"Statistic": "Average",
"Threshold": 0
}
},
"KinesisStream46752A3E": {
"Type": "AWS::Kinesis::Stream",
"Properties": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,32 @@
]
}
},
"ApiGatwayToKinesisStreamsKinesisStreamGetRecordsIteratorAgeAlarm1705B52A": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanOrEqualToThreshold",
"EvaluationPeriods": 1,
"AlarmDescription": "Consumer Record Processing Falling Behind, there is risk for data loss due to record expiration.",
"MetricName": "GetRecords.IteratorAgeMilliseconds",
"Namespace": "AWS/Kinesis",
"Period": 300,
"Statistic": "Maximum",
"Threshold": 2592000
}
},
"ApiGatwayToKinesisStreamsKinesisStreamReadProvisionedThroughputExceededAlarm69C57002": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"ComparisonOperator": "GreaterThanThreshold",
"EvaluationPeriods": 1,
"AlarmDescription": "Consumer Application is Reading at a Slower Rate Than Expected.",
"MetricName": "ReadProvisionedThroughputExceeded",
"Namespace": "AWS/Kinesis",
"Period": 300,
"Statistic": "Average",
"Threshold": 0
}
},
"KinesisStream46752A3E": {
"Type": "AWS::Kinesis::Stream",
"Properties": {
Expand Down