1
1
package com .amazon .aws .prototyping ;
2
2
3
+ import java .util .ArrayList ;
3
4
import java .util .Arrays ;
5
+ import java .util .Collections ;
6
+ import java .util .HashMap ;
4
7
import java .util .List ;
8
+ import java .util .Map ;
9
+
10
+ import org .apache .commons .collections4 .CollectionUtils ;
11
+
12
+ import com .amazon .aws .prototyping .apigateway .DocumentDbFunction ;
13
+ import com .amazon .aws .prototyping .apigateway .DynamoDBFunction ;
14
+ import com .amazon .aws .prototyping .apigateway .EC2Function ;
15
+ import com .amazon .aws .prototyping .apigateway .HttpFunction ;
16
+ import com .amazon .aws .prototyping .apigateway .JdbcFunction ;
17
+ import com .amazon .aws .prototyping .apigateway .JsonFunction ;
18
+ import com .amazon .aws .prototyping .apigateway .KinesisProduceFunction ;
19
+ import com .amazon .aws .prototyping .apigateway .S3Function ;
20
+ import com .amazon .aws .prototyping .apigateway .SnsFunction ;
21
+ import com .amazon .aws .prototyping .apigateway .SqsFunction ;
22
+ import com .amazon .aws .prototyping .eventsource .DynamoDBStreamFunction ;
23
+ import com .amazon .aws .prototyping .eventsource .KinesisConsumeFunction ;
24
+ import com .amazon .aws .prototyping .eventsource .SnsSubscribedFunction ;
25
+ import com .amazon .aws .prototyping .eventsource .SqsReceiveFunction ;
5
26
6
27
import software .amazon .awscdk .core .Construct ;
7
28
import software .amazon .awscdk .core .Duration ;
12
33
import software .amazon .awscdk .services .apigateway .Resource ;
13
34
import software .amazon .awscdk .services .apigateway .RestApi ;
14
35
import software .amazon .awscdk .services .apigateway .StageOptions ;
36
+ import software .amazon .awscdk .services .docdb .CfnDBCluster ;
37
+ import software .amazon .awscdk .services .docdb .CfnDBClusterParameterGroup ;
38
+ import software .amazon .awscdk .services .docdb .CfnDBInstance ;
39
+ import software .amazon .awscdk .services .docdb .CfnDBSubnetGroup ;
15
40
import software .amazon .awscdk .services .dynamodb .Attribute ;
16
41
import software .amazon .awscdk .services .dynamodb .AttributeType ;
17
42
import software .amazon .awscdk .services .dynamodb .GlobalSecondaryIndexProps ;
43
+ import software .amazon .awscdk .services .dynamodb .StreamViewType ;
18
44
import software .amazon .awscdk .services .dynamodb .Table ;
19
45
import software .amazon .awscdk .services .ec2 .AmazonLinuxGeneration ;
20
46
import software .amazon .awscdk .services .ec2 .AmazonLinuxImage ;
31
57
import software .amazon .awscdk .services .ec2 .Vpc ;
32
58
import software .amazon .awscdk .services .iam .Effect ;
33
59
import software .amazon .awscdk .services .iam .PolicyStatement ;
60
+ import software .amazon .awscdk .services .kinesis .Stream ;
34
61
import software .amazon .awscdk .services .lambda .Code ;
35
62
import software .amazon .awscdk .services .lambda .Function ;
36
63
import software .amazon .awscdk .services .lambda .Runtime ;
64
+ import software .amazon .awscdk .services .lambda .StartingPosition ;
65
+ import software .amazon .awscdk .services .lambda .eventsources .DynamoEventSource ;
66
+ import software .amazon .awscdk .services .lambda .eventsources .KinesisEventSource ;
67
+ import software .amazon .awscdk .services .lambda .eventsources .SnsEventSource ;
68
+ import software .amazon .awscdk .services .lambda .eventsources .SqsEventSource ;
37
69
import software .amazon .awscdk .services .rds .DatabaseInstance ;
38
70
import software .amazon .awscdk .services .rds .DatabaseInstanceEngine ;
39
71
import software .amazon .awscdk .services .s3 .Bucket ;
40
72
import software .amazon .awscdk .services .secretsmanager .Secret ;
41
73
import software .amazon .awscdk .services .secretsmanager .SecretStringGenerator ;
74
+ import software .amazon .awscdk .services .sns .Topic ;
75
+ import software .amazon .awscdk .services .sqs .Queue ;
42
76
43
77
public class CdkStack extends Stack {
44
78
public CdkStack (final Construct scope , final String id ) {
@@ -48,8 +82,8 @@ public CdkStack(final Construct scope, final String id) {
48
82
public CdkStack (final Construct scope , final String id , final StackProps props ) {
49
83
super (scope , id , props );
50
84
51
- StageOptions deployOptions = StageOptions . builder (). loggingLevel ( MethodLoggingLevel . INFO ). dataTraceEnabled ( true )
52
- .build ();
85
+ StageOptions deployOptions =
86
+ StageOptions . builder (). loggingLevel ( MethodLoggingLevel . INFO ). dataTraceEnabled ( true ) .build ();
53
87
RestApi api = RestApi .Builder .create (this , "JavaSamplesRestApi" ).deployOptions (deployOptions ).build ();
54
88
55
89
List <SubnetConfiguration > subnetConfigurations = Arrays .asList (
@@ -63,6 +97,10 @@ public CdkStack(final Construct scope, final String id, final StackProps props)
63
97
createEC2Sample (api , vpc );
64
98
createJsonSample (api );
65
99
createRdbSample (api , vpc );
100
+ createDocumentDbSample (api , vpc );
101
+ createKinesisSample (api );
102
+ createSqlSample (api );
103
+ createSnsSample (api );
66
104
}
67
105
68
106
private void createHttpSample (RestApi api ) {
@@ -95,7 +133,7 @@ private void createDynamoDbSample(RestApi api) {
95
133
Attribute attributeYear = Attribute .builder ().name ("year" ).type (AttributeType .NUMBER ).build ();
96
134
Attribute attributeTitle = Attribute .builder ().name ("title" ).type (AttributeType .STRING ).build ();
97
135
Table table = Table .Builder .create (this , "SampleTable" ).partitionKey (attributeYear ).sortKey (attributeTitle )
98
- .build ();
136
+ .stream ( StreamViewType . NEW_AND_OLD_IMAGES ). build ();
99
137
GlobalSecondaryIndexProps index = GlobalSecondaryIndexProps .builder ().indexName ("title-year-index" )
100
138
.partitionKey (attributeTitle ).sortKey (attributeYear ).build ();
101
139
table .addGlobalSecondaryIndex (index );
@@ -112,6 +150,11 @@ private void createDynamoDbSample(RestApi api) {
112
150
Resource dynamodbResource = api .getRoot ().addResource ("dynamodb" );
113
151
dynamodbResource .addMethod ("GET" , LambdaIntegration .Builder .create (getFunction ).proxy (true ).build ());
114
152
dynamodbResource .addMethod ("PUT" , LambdaIntegration .Builder .create (putFunction ).proxy (true ).build ());
153
+
154
+ Function streamFunction = createFunction (DynamoDBStreamFunction .class , "handle" );
155
+ DynamoEventSource eventSource =
156
+ DynamoEventSource .Builder .create (table ).startingPosition (StartingPosition .LATEST ).build ();
157
+ streamFunction .addEventSource (eventSource );
115
158
}
116
159
117
160
private void createEC2Sample (RestApi api , Vpc vpc ) {
@@ -121,20 +164,20 @@ private void createEC2Sample(RestApi api, Vpc vpc) {
121
164
.instanceType (InstanceType .of (InstanceClass .BURSTABLE2 , InstanceSize .MICRO )).vpc (vpc ).build ();
122
165
123
166
PolicyStatement describeInstancesPolicy = PolicyStatement .Builder .create ().effect (Effect .ALLOW )
124
- .actions (Arrays . asList ("ec2:describeInstances" )).resources (Arrays .asList ("*" )).build ();
167
+ .actions (Collections . singletonList ("ec2:describeInstances" )).resources (Arrays .asList ("*" )).build ();
125
168
126
169
Function startFunction = createFunction (EC2Function .class , "startAndWait" , Duration .minutes (3 ), null );
127
170
startFunction .addEnvironment ("INSTANCE_ID" , instance .getInstanceId ());
128
171
startFunction .addToRolePolicy (PolicyStatement .Builder .create ().effect (Effect .ALLOW )
129
- .actions (Arrays . asList ("ec2:startInstances" )).resources (Arrays .asList (String
172
+ .actions (Collections . singletonList ("ec2:startInstances" )).resources (Arrays .asList (String
130
173
.format ("arn:aws:ec2:%s:%s:instance/%s" , getRegion (), getAccount (), instance .getInstanceId ())))
131
174
.build ());
132
175
startFunction .addToRolePolicy (describeInstancesPolicy );
133
176
134
177
Function stopFunction = createFunction (EC2Function .class , "stopAndWait" , Duration .minutes (3 ), null );
135
178
stopFunction .addEnvironment ("INSTANCE_ID" , instance .getInstanceId ());
136
179
stopFunction .addToRolePolicy (PolicyStatement .Builder .create ().effect (Effect .ALLOW )
137
- .actions (Arrays . asList ("ec2:stopInstances" )).resources (Arrays .asList (String
180
+ .actions (Collections . singletonList ("ec2:stopInstances" )).resources (Arrays .asList (String
138
181
.format ("arn:aws:ec2:%s:%s:instance/%s" , getRegion (), getAccount (), instance .getInstanceId ())))
139
182
.build ());
140
183
stopFunction .addToRolePolicy (describeInstancesPolicy );
@@ -158,11 +201,12 @@ private void createJsonSample(RestApi api) {
158
201
}
159
202
160
203
private void createRdbSample (RestApi api , Vpc vpc ) {
161
- Secret secret = Secret .Builder .create (this , "RdsSampleUserPassword" )
162
- .generateSecretString (
163
- SecretStringGenerator .builder ().secretStringTemplate (String .format ("{\" username\" : \" test\" }" ))
204
+ Secret secret =
205
+ Secret .Builder .create (this , "RdsSampleUserPassword" )
206
+ .generateSecretString (SecretStringGenerator .builder ()
207
+ .secretStringTemplate (String .format ("{\" username\" : \" test\" }" ))
164
208
.generateStringKey ("password" ).excludePunctuation (true ).build ())
165
- .build ();
209
+ .build ();
166
210
167
211
String databaseName = "sample" ;
168
212
SecurityGroup rdsSecurityGroup = SecurityGroup .Builder .create (this , "SampleRdsSecurityGroup" ).vpc (vpc ).build ();
@@ -193,6 +237,108 @@ private void createRdbSample(RestApi api, Vpc vpc) {
193
237
LambdaIntegration .Builder .create (selectFunction ).proxy (true ).build ());
194
238
}
195
239
240
+ private void createDocumentDbSample (RestApi api , Vpc vpc ) {
241
+ Secret secret = Secret .Builder .create (this , "DocumentDbSampleUserPassword" )
242
+ .generateSecretString (SecretStringGenerator .builder ().secretStringTemplate ("{\" username\" : \" test\" }" )
243
+ .generateStringKey ("password" ).excludePunctuation (true ).build ())
244
+ .build ();
245
+
246
+ SecurityGroup securityGroup =
247
+ SecurityGroup .Builder .create (this , "SampleDocumentDBSecurityGroup" ).vpc (vpc ).build ();
248
+ securityGroup .addIngressRule (Peer .ipv4 (vpc .getVpcCidrBlock ()), Port .tcp (27017 ));
249
+
250
+ Map <String , String > parameterMap = new HashMap <>();
251
+ parameterMap .put ("tls" , "disabled" );
252
+ CfnDBClusterParameterGroup parameterGroup = CfnDBClusterParameterGroup .Builder
253
+ .create (this , "SampleDocumentDBParameterGroup" ).name ("sample-document-db-parameter-group" )
254
+ .description ("DBParameterGroup for SampleDocumentDBCluster" ).family ("docdb3.6" ).parameters (parameterMap )
255
+ .build ();
256
+
257
+ List <String > subnetIds =
258
+ new ArrayList <>(CollectionUtils .collect (vpc .getPrivateSubnets (), (subnet ) -> subnet .getSubnetId ()));
259
+ // both db subnet group name and cluster name need to be lower case, because it
260
+ // is changed to lower case by cdk for some reason.
261
+ CfnDBSubnetGroup subnetGroup = CfnDBSubnetGroup .Builder .create (this , "SampleDocumentDBSubnetGroup" )
262
+ .subnetIds (subnetIds ).dbSubnetGroupName ("sample-document-db-subnet-group" )
263
+ .dbSubnetGroupDescription ("DBSubnetGroup for SampleDocumentDBCluster" ).build ();
264
+
265
+ CfnDBCluster cluster = CfnDBCluster .Builder .create (this , "SampleDocumentDBCluster" )
266
+ .dbClusterIdentifier ("sample-document-db-cluster" ).dbClusterParameterGroupName (parameterGroup .getName ())
267
+ .dbSubnetGroupName (subnetGroup .getDbSubnetGroupName ())
268
+ .vpcSecurityGroupIds (Collections .singletonList (securityGroup .getSecurityGroupId ()))
269
+ .masterUsername (secret .secretValueFromJson ("username" ).toString ())
270
+ .masterUserPassword (secret .secretValueFromJson ("password" ).toString ()).build ();
271
+ cluster .addDependsOn (subnetGroup );
272
+
273
+ CfnDBInstance instance = CfnDBInstance .Builder .create (this , "SampleDocumentDB" )
274
+ .dbClusterIdentifier (cluster .getDbClusterIdentifier ()).dbInstanceClass ("db.r5.large" ).build ();
275
+ instance .addDependsOn (cluster );
276
+
277
+ Function insertFunction = createFunction (DocumentDbFunction .class , "insert" , Duration .seconds (30 ), vpc );
278
+ Function deleteFunction = createFunction (DocumentDbFunction .class , "delete" , Duration .seconds (30 ), vpc );
279
+ Function findFunction = createFunction (DocumentDbFunction .class , "find" , Duration .seconds (30 ), vpc );
280
+
281
+ for (Function function : Arrays .asList (insertFunction , deleteFunction , findFunction )) {
282
+ function .addEnvironment ("CLUSTER_ENDPOINT" , cluster .getAttrEndpoint ());
283
+ function .addEnvironment ("SECRET_ARN" , secret .getSecretArn ());
284
+ secret .grantRead (function );
285
+ }
286
+
287
+ Resource documentDbResource = api .getRoot ().addResource ("documentdb" );
288
+ documentDbResource .addResource ("insert" ).addMethod ("POST" ,
289
+ LambdaIntegration .Builder .create (insertFunction ).proxy (true ).build ());
290
+ documentDbResource .addResource ("delete" ).addMethod ("POST" ,
291
+ LambdaIntegration .Builder .create (deleteFunction ).proxy (true ).build ());
292
+ documentDbResource .addResource ("find" ).addMethod ("GET" ,
293
+ LambdaIntegration .Builder .create (findFunction ).proxy (true ).build ());
294
+ }
295
+
296
+ private void createKinesisSample (RestApi api ) {
297
+ Stream stream = Stream .Builder .create (this , "SampleKinesisStream" ).build ();
298
+
299
+ Function putRecordFunction = createFunction (KinesisProduceFunction .class , "putRecord" );
300
+ putRecordFunction .addEnvironment ("KINESIS_STREAM_NAME" , stream .getStreamName ());
301
+ stream .grantWrite (putRecordFunction );
302
+
303
+ api .getRoot ().addResource ("kinesis" ).addMethod ("PUT" ,
304
+ LambdaIntegration .Builder .create (putRecordFunction ).proxy (true ).build ());
305
+
306
+ Function function = createFunction (KinesisConsumeFunction .class , "handle" );
307
+
308
+ KinesisEventSource eventSource =
309
+ KinesisEventSource .Builder .create (stream ).startingPosition (StartingPosition .TRIM_HORIZON ).build ();
310
+ function .addEventSource (eventSource );
311
+ }
312
+
313
+ private void createSqlSample (RestApi api ) {
314
+ Queue queue = Queue .Builder .create (this , "SampleSqsQueue" ).build ();
315
+
316
+ Function sendFunction = createFunction (SqsFunction .class , "send" );
317
+ queue .grantSendMessages (sendFunction );
318
+ sendFunction .addEnvironment ("QUEUE_URL" , queue .getQueueUrl ());
319
+
320
+ api .getRoot ().addResource ("sqs" ).addMethod ("PUT" ,
321
+ LambdaIntegration .Builder .create (sendFunction ).proxy (true ).build ());
322
+
323
+ Function receiveFunction = createFunction (SqsReceiveFunction .class , "handle" );
324
+ SqsEventSource eventSource = SqsEventSource .Builder .create (queue ).build ();
325
+ receiveFunction .addEventSource (eventSource );
326
+ }
327
+
328
+ private void createSnsSample (RestApi api ) {
329
+ Topic topic = Topic .Builder .create (this , "SampleTopic" ).build ();
330
+
331
+ Function publishFunction = createFunction (SnsFunction .class , "publish" );
332
+ topic .grantPublish (publishFunction );
333
+ publishFunction .addEnvironment ("TOPIC_ARN" , topic .getTopicArn ());
334
+
335
+ api .getRoot ().addResource ("sns" ).addMethod ("POST" ,
336
+ LambdaIntegration .Builder .create (publishFunction ).proxy (true ).build ());
337
+
338
+ Function subscribedFunction = createFunction (SnsSubscribedFunction .class , "handle" );
339
+ subscribedFunction .addEventSource (new SnsEventSource (topic ));
340
+ }
341
+
196
342
private Function createFunction (Class <?> functionClass , String handler ) {
197
343
return createFunction (functionClass , handler , Duration .seconds (10 ), null );
198
344
}
0 commit comments