1616
1717import static java .util .Collections .singletonList ;
1818
19- import com .fasterxml .jackson .databind .JsonNode ;
2019import java .io .File ;
2120import java .io .IOException ;
2221import java .nio .file .Paths ;
2726import java .util .Objects ;
2827import java .util .UUID ;
2928import java .util .stream .Collectors ;
29+
3030import org .slf4j .Logger ;
3131import org .slf4j .LoggerFactory ;
3232import org .yaml .snakeyaml .Yaml ;
33+
34+ import com .fasterxml .jackson .databind .JsonNode ;
35+
3336import software .amazon .awscdk .App ;
3437import software .amazon .awscdk .BundlingOptions ;
3538import software .amazon .awscdk .BundlingOutput ;
3639import software .amazon .awscdk .CfnOutput ;
40+ import software .amazon .awscdk .DefaultStackSynthesizer ;
3741import software .amazon .awscdk .DockerVolume ;
3842import software .amazon .awscdk .Duration ;
3943import software .amazon .awscdk .RemovalPolicy ;
4549import software .amazon .awscdk .services .appconfig .CfnDeploymentStrategy ;
4650import software .amazon .awscdk .services .appconfig .CfnEnvironment ;
4751import software .amazon .awscdk .services .appconfig .CfnHostedConfigurationVersion ;
48- import software .amazon .awscdk .services .dynamodb .*;
52+ import software .amazon .awscdk .services .dynamodb .Attribute ;
53+ import software .amazon .awscdk .services .dynamodb .AttributeType ;
54+ import software .amazon .awscdk .services .dynamodb .BillingMode ;
55+ import software .amazon .awscdk .services .dynamodb .StreamViewType ;
56+ import software .amazon .awscdk .services .dynamodb .Table ;
4957import software .amazon .awscdk .services .iam .PolicyStatement ;
5058import software .amazon .awscdk .services .kinesis .Stream ;
5159import software .amazon .awscdk .services .kinesis .StreamMode ;
8997 * CloudWatch log groups, ...
9098 * <br/>
9199 * It uses the Cloud Development Kit (CDK) to define required resources. The CDK stack is then synthesized to retrieve
92- * the CloudFormation templates and the assets (function jars). Assets are uploaded to S3 (with the SDK `PutObjectRequest`)
100+ * the CloudFormation templates and the assets (function jars). Assets are uploaded to S3 (with the SDK
101+ * `PutObjectRequest`)
93102 * and the CloudFormation stack is created (with the SDK `createStack`)
94103 */
95104public class Infrastructure {
@@ -174,11 +183,11 @@ public Map<String, String> deploy() {
174183 .onFailure (OnFailure .ROLLBACK )
175184 .capabilities (Capability .CAPABILITY_IAM )
176185 .build ());
177- WaiterResponse <DescribeStacksResponse > waiterResponse =
178- cfn . waiter () .waitUntilStackCreateComplete (DescribeStacksRequest .builder ().stackName (stackName ).build ());
186+ WaiterResponse <DescribeStacksResponse > waiterResponse = cfn . waiter ()
187+ .waitUntilStackCreateComplete (DescribeStacksRequest .builder ().stackName (stackName ).build ());
179188 if (waiterResponse .matched ().response ().isPresent ()) {
180- software .amazon .awssdk .services .cloudformation .model .Stack deployedStack =
181- waiterResponse . matched () .response ().get ().stacks ().get (0 );
189+ software .amazon .awssdk .services .cloudformation .model .Stack deployedStack = waiterResponse . matched ()
190+ .response ().get ().stacks ().get (0 );
182191 LOG .info ("Stack " + deployedStack .stackName () + " successfully deployed" );
183192 Map <String , String > outputs = new HashMap <>();
184193 deployedStack .outputs ().forEach (output -> outputs .put (output .outputKey (), output .outputValue ()));
@@ -203,7 +212,11 @@ public void destroy() {
203212 */
204213 private Stack createStackWithLambda () {
205214 boolean createTableForAsyncTests = false ;
206- Stack stack = new Stack (app , stackName );
215+ final Stack e2eStack = Stack .Builder .create (app , stackName )
216+ .synthesizer (DefaultStackSynthesizer .Builder .create ()
217+ .generateBootstrapVersionRule (false ) // Disable bootstrap version check
218+ .build ())
219+ .build ();
207220
208221 List <String > packagingInstruction = Arrays .asList (
209222 "/bin/sh" ,
@@ -213,8 +226,7 @@ private Stack createStackWithLambda() {
213226 " -Dmaven.test.skip=true " +
214227 " -Dmaven.compiler.source=" + runtime .getMvnProperty () +
215228 " -Dmaven.compiler.target=" + runtime .getMvnProperty () +
216- " && cp /asset-input/" + pathToFunction + "/target/function.jar /asset-output/"
217- );
229+ " && cp /asset-input/" + pathToFunction + "/target/function.jar /asset-output/" );
218230
219231 BundlingOptions .Builder builderOptions = BundlingOptions .builder ()
220232 .command (packagingInstruction )
@@ -224,20 +236,19 @@ private Stack createStackWithLambda() {
224236 DockerVolume .builder ()
225237 .hostPath (System .getProperty ("user.home" ) + "/.m2/" )
226238 .containerPath ("/root/.m2/" )
227- .build ()
228- ))
239+ .build ()))
229240 .user ("root" )
230241 .outputType (BundlingOutput .ARCHIVED );
231242
232243 functionName = stackName + "-function" ;
233- CfnOutput .Builder .create (stack , FUNCTION_NAME_OUTPUT )
244+ CfnOutput .Builder .create (e2eStack , FUNCTION_NAME_OUTPUT )
234245 .value (functionName )
235246 .build ();
236247
237248 LOG .debug ("Building Lambda function with command " +
238249 packagingInstruction .stream ().collect (Collectors .joining (" " , "[" , "]" )));
239250 Function function = Function .Builder
240- .create (stack , functionName )
251+ .create (e2eStack , functionName )
241252 .code (Code .fromAsset ("handlers/" , AssetOptions .builder ()
242253 .bundling (builderOptions
243254 .command (packagingInstruction )
@@ -253,15 +264,15 @@ private Stack createStackWithLambda() {
253264 .build ();
254265
255266 LogGroup .Builder
256- .create (stack , functionName + "-logs" )
267+ .create (e2eStack , functionName + "-logs" )
257268 .logGroupName ("/aws/lambda/" + functionName )
258269 .retention (RetentionDays .ONE_DAY )
259270 .removalPolicy (RemovalPolicy .DESTROY )
260271 .build ();
261272
262273 if (!StringUtils .isEmpty (idempotencyTable )) {
263274 Table table = Table .Builder
264- .create (stack , "IdempotencyTable" )
275+ .create (e2eStack , "IdempotencyTable" )
265276 .billingMode (BillingMode .PAY_PER_REQUEST )
266277 .removalPolicy (RemovalPolicy .DESTROY )
267278 .partitionKey (Attribute .builder ().name ("id" ).type (AttributeType .STRING ).build ())
@@ -275,7 +286,7 @@ private Stack createStackWithLambda() {
275286
276287 if (!StringUtils .isEmpty (queue )) {
277288 Queue sqsQueue = Queue .Builder
278- .create (stack , "SQSQueue" )
289+ .create (e2eStack , "SQSQueue" )
279290 .queueName (queue )
280291 .visibilityTimeout (Duration .seconds (timeout * 6 ))
281292 .retentionPeriod (Duration .seconds (timeout * 6 ))
@@ -293,14 +304,14 @@ private Stack createStackWithLambda() {
293304 .build ();
294305 function .addEventSource (sqsEventSource );
295306 CfnOutput .Builder
296- .create (stack , "QueueURL" )
307+ .create (e2eStack , "QueueURL" )
297308 .value (sqsQueue .getQueueUrl ())
298309 .build ();
299310 createTableForAsyncTests = true ;
300311 }
301312 if (!StringUtils .isEmpty (kinesisStream )) {
302313 Stream stream = Stream .Builder
303- .create (stack , "KinesisStream" )
314+ .create (e2eStack , "KinesisStream" )
304315 .streamMode (StreamMode .ON_DEMAND )
305316 .streamName (kinesisStream )
306317 .build ();
@@ -316,13 +327,13 @@ private Stack createStackWithLambda() {
316327 .build ();
317328 function .addEventSource (kinesisEventSource );
318329 CfnOutput .Builder
319- .create (stack , "KinesisStreamName" )
330+ .create (e2eStack , "KinesisStreamName" )
320331 .value (stream .getStreamName ())
321332 .build ();
322333 }
323334
324335 if (!StringUtils .isEmpty (ddbStreamsTableName )) {
325- Table ddbStreamsTable = Table .Builder .create (stack , "DDBStreamsTable" )
336+ Table ddbStreamsTable = Table .Builder .create (e2eStack , "DDBStreamsTable" )
326337 .tableName (ddbStreamsTableName )
327338 .stream (StreamViewType .KEYS_ONLY )
328339 .removalPolicy (RemovalPolicy .DESTROY )
@@ -336,12 +347,12 @@ private Stack createStackWithLambda() {
336347 .reportBatchItemFailures (true )
337348 .build ();
338349 function .addEventSource (ddbEventSource );
339- CfnOutput .Builder .create (stack , "DdbStreamsTestTable" ).value (ddbStreamsTable .getTableName ()).build ();
350+ CfnOutput .Builder .create (e2eStack , "DdbStreamsTestTable" ).value (ddbStreamsTable .getTableName ()).build ();
340351 }
341352
342353 if (!StringUtils .isEmpty (largeMessagesBucket )) {
343354 Bucket offloadBucket = Bucket .Builder
344- .create (stack , "LargeMessagesOffloadBucket" )
355+ .create (e2eStack , "LargeMessagesOffloadBucket" )
345356 .removalPolicy (RemovalPolicy .RETAIN ) // autodelete does not work without cdk deploy
346357 .bucketName (largeMessagesBucket )
347358 .build ();
@@ -352,19 +363,19 @@ private Stack createStackWithLambda() {
352363
353364 if (appConfig != null ) {
354365 CfnApplication app = CfnApplication .Builder
355- .create (stack , "AppConfigApp" )
366+ .create (e2eStack , "AppConfigApp" )
356367 .name (appConfig .getApplication ())
357368 .build ();
358369
359370 CfnEnvironment environment = CfnEnvironment .Builder
360- .create (stack , "AppConfigEnvironment" )
371+ .create (e2eStack , "AppConfigEnvironment" )
361372 .applicationId (app .getRef ())
362373 .name (appConfig .getEnvironment ())
363374 .build ();
364375
365376 // Create a fast deployment strategy, so we don't have to wait ages
366377 CfnDeploymentStrategy fastDeployment = CfnDeploymentStrategy .Builder
367- .create (stack , "AppConfigDeployment" )
378+ .create (e2eStack , "AppConfigDeployment" )
368379 .name ("FastDeploymentStrategy" )
369380 .deploymentDurationInMinutes (0 )
370381 .finalBakeTimeInMinutes (0 )
@@ -377,28 +388,27 @@ private Stack createStackWithLambda() {
377388 .create ()
378389 .actions (singletonList ("appconfig:*" ))
379390 .resources (singletonList ("*" ))
380- .build ()
381- );
391+ .build ());
382392
383393 CfnDeployment previousDeployment = null ;
384394 for (Map .Entry <String , String > entry : appConfig .getConfigurationValues ().entrySet ()) {
385395 CfnConfigurationProfile configProfile = CfnConfigurationProfile .Builder
386- .create (stack , "AppConfigProfileFor" + entry .getKey ())
396+ .create (e2eStack , "AppConfigProfileFor" + entry .getKey ())
387397 .applicationId (app .getRef ())
388398 .locationUri ("hosted" )
389399 .name (entry .getKey ())
390400 .build ();
391401
392402 CfnHostedConfigurationVersion configVersion = CfnHostedConfigurationVersion .Builder
393- .create (stack , "AppConfigHostedVersionFor" + entry .getKey ())
403+ .create (e2eStack , "AppConfigHostedVersionFor" + entry .getKey ())
394404 .applicationId (app .getRef ())
395405 .contentType ("text/plain" )
396406 .configurationProfileId (configProfile .getRef ())
397407 .content (entry .getValue ())
398408 .build ();
399409
400410 CfnDeployment deployment = CfnDeployment .Builder
401- .create (stack , "AppConfigDepoymentFor" + entry .getKey ())
411+ .create (e2eStack , "AppConfigDepoymentFor" + entry .getKey ())
402412 .applicationId (app .getRef ())
403413 .environmentId (environment .getRef ())
404414 .deploymentStrategyId (fastDeployment .getRef ())
@@ -415,7 +425,7 @@ private Stack createStackWithLambda() {
415425 }
416426 if (createTableForAsyncTests ) {
417427 Table table = Table .Builder
418- .create (stack , "TableForAsyncTests" )
428+ .create (e2eStack , "TableForAsyncTests" )
419429 .billingMode (BillingMode .PAY_PER_REQUEST )
420430 .removalPolicy (RemovalPolicy .DESTROY )
421431 .partitionKey (Attribute .builder ().name ("functionName" ).type (AttributeType .STRING ).build ())
@@ -424,10 +434,10 @@ private Stack createStackWithLambda() {
424434
425435 table .grantReadWriteData (function );
426436 function .addEnvironment ("TABLE_FOR_ASYNC_TESTS" , table .getTableName ());
427- CfnOutput .Builder .create (stack , "TableNameForAsyncTests" ).value (table .getTableName ()).build ();
437+ CfnOutput .Builder .create (e2eStack , "TableNameForAsyncTests" ).value (table .getTableName ()).build ();
428438 }
429439
430- return stack ;
440+ return e2eStack ;
431441 }
432442
433443 /**
@@ -444,13 +454,13 @@ private void synthesize() {
444454 */
445455 private void uploadAssets () {
446456 Map <String , Asset > assets = findAssets ();
447- assets .forEach ((objectKey , asset ) ->
448- {
457+ assets .forEach ((objectKey , asset ) -> {
449458 if (!asset .assetPath .endsWith (".jar" )) {
450459 return ;
451460 }
452- ListObjectsV2Response objects =
453- s3 .listObjectsV2 (ListObjectsV2Request .builder ().bucket (asset .bucketName ).build ());
461+
462+ ListObjectsV2Response objects = s3
463+ .listObjectsV2 (ListObjectsV2Request .builder ().bucket (asset .bucketName ).build ());
454464 if (objects .contents ().stream ().anyMatch (o -> o .key ().equals (objectKey ))) {
455465 LOG .debug ("Asset already exists, skipping" );
456466 return ;
@@ -472,14 +482,13 @@ private Map<String, Asset> findAssets() {
472482 JsonNode jsonNode = JsonConfig .get ().getObjectMapper ()
473483 .readTree (new File (cfnAssetDirectory , stackName + ".assets.json" ));
474484 JsonNode files = jsonNode .get ("files" );
475- files .iterator ().forEachRemaining (file ->
476- {
485+ files .iterator ().forEachRemaining (file -> {
477486 String assetPath = file .get ("source" ).get ("path" ).asText ();
478487 String assetPackaging = file .get ("source" ).get ("packaging" ).asText ();
479- String bucketName =
480- file . get ( "destinations" ). get ( "current_account-current_region" ). get ( "bucketName" ) .asText ();
481- String objectKey =
482- file . get ( "destinations" ). get ( "current_account-current_region" ). get ( "objectKey" ) .asText ();
488+ String bucketName = file . get ( "destinations" ). get ( "current_account-current_region" ). get ( "bucketName" )
489+ .asText ();
490+ String objectKey = file . get ( "destinations" ). get ( "current_account-current_region" ). get ( "objectKey" )
491+ .asText ();
483492 Asset asset = new Asset (assetPath , assetPackaging , bucketName .replace ("${AWS::AccountId}" , account )
484493 .replace ("${AWS::Region}" , region .toString ()));
485494 assets .put (objectKey , asset );
@@ -509,8 +518,6 @@ private Builder() {
509518 runtime = mapRuntimeVersion ("JAVA_VERSION" );
510519 }
511520
512-
513-
514521 private JavaRuntime mapRuntimeVersion (String environmentVariableName ) {
515522 String javaVersion = System .getenv (environmentVariableName ); // must be set in GitHub actions
516523 JavaRuntime ret = null ;
0 commit comments