Skip to content
This repository was archived by the owner on Jul 16, 2024. It is now read-only.

Commit 6d00096

Browse files
authored
fix: unique lambda function name in prebundled function (#395)
1 parent 4fddea8 commit 6d00096

15 files changed

+118
-77
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ refarch/aws-native/dwh/dwh_loader_layer
2121
refarch/aws-native/streaming/streaming_cdk/lambda-layer
2222
refarch/aws-native/streaming/stream-processing/target
2323
core/node_modules/
24+
core/src/integ.default.ts
2425
*.log
2526
doc/site
2627
__init__.py

CONTRIB_FAQ.md

+63-10
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,52 @@ Put relevant type of contribution in the commit message. This message is used to
120120
* Typedoc (https://typedoc.org/guides/doccomments/) for code comments and API documentation in the framework (./core). See the `ExampleProps` interface and `Example` class [here](https://github.com/aws-samples/aws-analytics-reference-architecture/blob/main/core/src/example.ts)
121121
* Pdoc3 (https://pdoc3.github.io/pdoc/) for code comments and API documentation of reference architectures (./refarch)
122122

123+
Examples can be found in the current code documentation used by [Construct Hub](https://constructs.dev/packages/aws-analytics-reference-architecture). For example here is the code comment for the DataLakeStorage construct:
124+
125+
```
126+
/**
127+
* A CDK Construct that creates the storage layers of a data lake composed of Amazon S3 Buckets.
128+
*
129+
* This construct is based on 3 Amazon S3 buckets configured with AWS best practices:
130+
* * S3 buckets for Raw/Cleaned/Transformed data,
131+
* * data lifecycle optimization/transitioning to different Amazon S3 storage classes
132+
* * server side buckets encryption managed by KMS customer key
133+
* * Default single KMS key
134+
* * SSL communication enforcement
135+
* * access logged to an S3 bucket
136+
* * All public access blocked
137+
*
138+
* By default the transitioning rules to Amazon S3 storage classes are configured as following:
139+
* * Raw data is moved to Infrequent Access after 30 days and archived to Glacier after 90 days
140+
* * Clean and Transformed data is moved to Infrequent Access after 90 days and is not archived
141+
*
142+
* Objects and buckets are automatically deleted when the CDK application is detroyed.
143+
*
144+
* For custom requirements, consider using {@link AraBucket}.
145+
*
146+
* Usage example:
147+
* ```typescript
148+
* import * as cdk from 'aws-cdk-lib';
149+
* import { DataLakeStorage } from 'aws-analytics-reference-architecture';
150+
*
151+
* const exampleApp = new cdk.App();
152+
* const stack = new cdk.Stack(exampleApp, 'DataLakeStorageStack');
153+
*
154+
* new DataLakeStorage(stack, 'MyDataLakeStorage', {
155+
* rawInfrequentAccessDelay: 90,
156+
* rawArchiveDelay: 180,
157+
* cleanInfrequentAccessDelay: 180,
158+
* cleanArchiveDelay: 360,
159+
* transformInfrequentAccessDelay: 180,
160+
* transformArchiveDelay: 360,
161+
* });
162+
* ```
163+
*/
164+
```
165+
166+
And [how it renders in Construct Hub](https://constructs.dev/packages/aws-analytics-reference-architecture/v/2.1.0/api/DataLakeStorage?lang=python).
167+
168+
123169
## CDK best practices
124170

125171
### What are the coding best practices and patterns with CDK
@@ -267,13 +313,18 @@ Thus, we choose to prebundle Lambda function by installing all dependencies on p
267313

268314
## Testing
269315

270-
#### How to test CDK Constructs logic with a deployment in AWS Account?
316+
### What are the required tests to implement?
271317

272-
AWS CDK logic can be tested by deploying a stack that instantiates AWS CDK components. Projen is configured to provide extra actions `test:deploy` and `test:destroy` to deploy in a testing account and destroy. [`./core/src/integ.default.ts`](./core/src/integ.default.ts) can be customized to deploy Constructs.
318+
It's required to implement 3 types of test:
319+
* Unit tests (in `core/test/unit`): validate the CloudFormation that is generated by CDK
320+
* CDK-nag tests (in `core/test/unit/cdk-nag`): validate the CDK resources with [CDK-nag](https://github.com/cdklabs/cdk-nag) and the [AWS Solutions rule pack](https://github.com/cdklabs/cdk-nag/blob/main/RULES.md#awssolutions)
321+
* End-to-end tests (in `core/test/e2e`): validate the CDK resources can be deployed in an account, and the resources are running as expected. **It's strongly recommended to test the deployment of 2 resources to validate the unicity of CDK IDs and resource names**
273322

274-
### How to test private class members or methods in Typescript?
323+
### How to test CDK Constructs logic with a deployment in AWS Account?
324+
325+
AWS CDK logic can be tested by deploying a stack that instantiates AWS CDK components. Projen is configured to provide extra actions `test:deploy` and `test:destroy` to deploy in a testing account and destroy. [`./core/src/integ.default.ts`](./core/src/integ.default.ts) can be customized to deploy Constructs.
275326

276-
Typescript allows to access private members and methods using this syntax `customDataset["sqlTable"]()`. See example of testing `sqlTable()`private method from `Dataset` class [here](./core/test/dataset.test.ts)
327+
Remember to not commit any personal information like account IDs and role name in this file.
277328

278329
### How to test the core components library in local
279330

@@ -283,12 +334,14 @@ Typescript allows to access private members and methods using this syntax `custo
283334
npx projen package
284335
```
285336

286-
* For Python, create a new AWS CDK application in Python outside of this project and install a local dependency pointing to the `wheel` file in `core/dist/python`. In the `setup.py`, modify the dependencies like this
337+
* For Python, create a new AWS CDK application in Python outside of this project and install a local dependency pointing to the `wheel` file in `core/dist/python`. In the `requirements.txt`, modify the dependencies like this
287338

288-
```python
289-
install_requires=[
290-
"aws-cdk.core==1.130.0",
291-
f"aws_analytics_reference_architecture @ file:///localhost<LOCAL_PATH>/aws-analytics-reference-architecture/core/dist/python/aws_analytics_reference_architecture-0.0.0-py3-none-any.whl",
292-
],
293339
```
340+
aws-cdk.core==2.27.0
341+
constructs>=10.0.0,<11.0.0
342+
<LOCAL_PATH>/aws-analytics-reference-architecture/core/dist/python/aws_analytics_reference_architecture-0.0.0-py3-none-any.whl
343+
```
344+
345+
### How to test private class members or methods in Typescript?
294346

347+
Typescript allows to access private members and methods using this syntax `customDataset["sqlTable"]()`. See example of testing `sqlTable()`private method from `Dataset` class [here](./core/test/dataset.test.ts)

core/src/common/pre-bundled-function.ts

+5-18
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import * as path from 'path';
55
import { Effect, ManagedPolicy, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
6-
import { Code, Function, FunctionProps, ILayerVersion } from 'aws-cdk-lib/aws-lambda';
6+
import { Code, Function, FunctionProps } from 'aws-cdk-lib/aws-lambda';
77
import { Aws } from 'aws-cdk-lib';
88
// import { PreBundledLayer } from './pre-bundled-layer';
99
import { Construct } from 'constructs';
@@ -15,9 +15,7 @@ import { Construct } from 'constructs';
1515
*/
1616
export interface PreBundledFunctionProps extends Partial<FunctionProps> {
1717
codePath: string;
18-
name: string;
1918
lambdaPolicyStatements?: PolicyStatement[];
20-
lambdaLayers?: ILayerVersion[];
2119
}
2220

2321
/**
@@ -41,14 +39,13 @@ export interface PreBundledFunctionProps extends Partial<FunctionProps> {
4139
*
4240
* new PreBundledFunction(this, 'PreBundledFunction', {
4341
* codePath: 'construct-dir/resources/lambdas/lambda_dir',
42+
* lambdaPolicyStatements: findFilePathsFnPolicy,
4443
* // you can use any property available in Function CDK Construct including
45-
* name: 'myFunctionName',
4644
* memorySize: 1024,
4745
* runtime: Runtime.PYTHON_3_8,
4846
* handler: 'lmabda-file-name.handler',
4947
* logRetention: RetentionDays.ONE_WEEK,
5048
* timeout: Duration.minutes(15),
51-
* lambdaPolicyStatements: findFilePathsFnPolicy,
5249
* });
5350
* ```
5451
*/
@@ -73,7 +70,7 @@ export class PreBundledFunction extends Function {
7370
let assetPath = path.join(__dirname, `../${props.codePath}`);
7471

7572
functionProps.code = Code.fromAsset(assetPath);
76-
functionProps.functionName = props.name.slice();
73+
functionProps.functionName = `${scope.node.id}${id}`;
7774

7875
let lambdaPolicyStatement: PolicyStatement[] = [];
7976

@@ -111,7 +108,7 @@ export class PreBundledFunction extends Function {
111108
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
112109
description: 'Role used by lambda in ARA',
113110
managedPolicies: [lambdaExecutionRolePolicy],
114-
roleName: 'LambdaExecutionRole' + functionProps.functionName,
111+
//roleName: 'LambdaExecutionRole' + functionProps.functionName,
115112
});
116113

117114
let logRetentionLambdaPolicyStatement: PolicyStatement[] = [];
@@ -140,26 +137,16 @@ export class PreBundledFunction extends Function {
140137
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
141138
description: 'Role used by lambda to modify log retention',
142139
managedPolicies: [logRetentionLambdaExecutionRolePolicy],
143-
roleName: 'LogRetLambdaExec' + functionProps.functionName,
140+
//roleName: 'LogRetLambdaExec' + functionProps.functionName,
144141
});
145142

146143
functionProps.role = lambdaExecutionRole;
147144
functionProps.logRetentionRole = logRetentionLambdaExecutionRole;
148145

149-
150-
// const runtimes = Object.values([Runtime.PYTHON_3_8, Runtime.PYTHON_3_7, Runtime.PYTHON_3_9]);
151-
// let layers: ILayerVersion[] = [];
152-
153-
// If the runtime is Python we use the common Lambda Layer with boto3
154-
// if (runtimes.includes(functionProps.runtime as Runtime)) {
155-
// layers.push(PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer'));
156-
// }
157-
158146
//delete props that were added to force user input
159147
delete functionProps.codePath;
160148
delete functionProps.name;
161149
delete functionProps.lambdaPolicyStatements;
162-
delete functionProps.lambdaLayers;
163150

164151
super(scope, id, { ...(functionProps as FunctionProps) });
165152
}

core/src/data-generator/batch-replayer.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ export class BatchReplayer extends Construct {
145145
* Find all paths within the time range from the manifest file
146146
*/
147147
const findFilePathsFn = new PreBundledFunction(this, 'FindFilePath', {
148-
name: 'FindFilePathsFn',
149148
memorySize: 1024,
150149
codePath: 'data-generator/resources/lambdas/find-file-paths',
151150
runtime: Runtime.PYTHON_3_9,
@@ -187,8 +186,7 @@ export class BatchReplayer extends Construct {
187186
* Rewrite data
188187
*/
189188
const writeInBatchFn = new PreBundledFunction(this, 'WriteInBatch', {
190-
name: 'WriteInBatchFn',
191-
memorySize: 1024 * 5,
189+
memorySize: 1024 * 3,
192190
codePath: 'data-generator/resources/lambdas/write-in-batch',
193191
runtime: Runtime.PYTHON_3_9,
194192
handler: 'write-in-batch.handler',

core/src/db-schema-manager/flyway-runner.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,8 @@ export class FlywayRunner extends Construct {
160160
}),
161161
];
162162

163-
const flywayLambda = new PreBundledFunction(this, 'runner', {
163+
const flywayLambda = new PreBundledFunction(this, 'FlywayLambda', {
164164
codePath: path.join(__dirname.split('/').slice(-1)[0], './resources/flyway-lambda/flyway-all.jar'),
165-
name: 'flywayLambda',
166165
lambdaPolicyStatements: flywayLambdaPolicy,
167166
handler: 'com.geekoosh.flyway.FlywayCustomResourceHandler::handleRequest',
168167
runtime: lambda.Runtime.JAVA_11,

core/src/emr-eks-platform/emr-eks-nodegroup-asg-tag.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,10 @@ export class EmrEksNodegroupAsgTagProvider extends Construct {
6969
];
7070

7171
// AWS Lambda function supporting the create, update, delete operations on Amazon EMR on EKS managed endpoints
72-
const onEvent = new PreBundledFunction(this, 'OnEvent', {
72+
const onEvent = new PreBundledFunction(this, 'Tag', {
7373
runtime: Runtime.PYTHON_3_9,
7474
codePath: 'emr-eks-platform/resources/lambdas/nodegroup-asg-tag',
7575
handler: 'lambda.on_event',
76-
name: 'EmrEksNodegroupAsgTagOnEventFn',
7776
lambdaPolicyStatements: lambdaPolicy,
7877
logRetention: RetentionDays.ONE_WEEK,
7978
layers: [PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer')],

core/src/emr-eks-platform/emr-managed-endpoint.ts

-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ export class EmrManagedEndpointProvider extends Construct {
113113
codePath: 'emr-eks-platform/resources/lambdas/managed-endpoint',
114114
runtime: Runtime.PYTHON_3_9,
115115
handler: 'lambda.on_event',
116-
name: 'EmrManagedEndpointProviderOnEvent',
117116
layers: [PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer')],
118117
lambdaPolicyStatements: lambdaPolicy,
119118
logRetention: RetentionDays.ONE_WEEK,
@@ -124,7 +123,6 @@ export class EmrManagedEndpointProvider extends Construct {
124123
const isComplete = new PreBundledFunction(this, 'IsComplete', {
125124
codePath: 'emr-eks-platform/resources/lambdas/managed-endpoint',
126125
handler: 'lambda.is_complete',
127-
name: 'EmrManagedEndpointProviderIsComplete',
128126
layers: [PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer')],
129127
lambdaPolicyStatements: lambdaPolicy,
130128
runtime: Runtime.PYTHON_3_9,

core/src/synchronous-athena-query/synchronous-athena-query.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,9 @@ export class SynchronousAthenaQuery extends Construct {
113113

114114

115115
// AWS Lambda function for the AWS CDK Custom Resource responsible to start query
116-
const athenaQueryStartFn = new PreBundledFunction(this, 'AthenaQueryStartFn', {
116+
const athenaQueryStartFn = new PreBundledFunction(this, 'StartFn', {
117117
runtime: Runtime.PYTHON_3_9,
118118
codePath: 'synchronous-athena-query/resources/lambdas',
119-
name: 'SynchronousAthenaCrStart',
120119
layers: [PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer')],
121120
lambdaPolicyStatements: athenaQueryStartFnPolicy,
122121
handler: 'lambda.on_event',
@@ -144,10 +143,9 @@ export class SynchronousAthenaQuery extends Construct {
144143
}));
145144

146145
// AWS Lambda function for the AWS CDK Custom Resource responsible to wait for query completion
147-
const athenaQueryWaitFn = new PreBundledFunction(this, 'AthenaQueryWaitFn', {
146+
const athenaQueryWaitFn = new PreBundledFunction(this, 'WaitFn', {
148147
runtime: Runtime.PYTHON_3_9,
149148
codePath: 'synchronous-athena-query/resources/lambdas',
150-
name: 'SynchronousAthenaCrWait',
151149
layers: [PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer')],
152150
lambdaPolicyStatements: athenaQueryWaitFnPolicy,
153151
handler: 'lambda.is_complete',

core/src/synchronous-crawler/synchronous-crawler.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,9 @@ export class SynchronousCrawler extends Construct {
6464
})];
6565

6666
// AWS Lambda function for the AWS CDK Custom Resource responsible to start crawler
67-
const crawlerStartFn = new PreBundledFunction(this, 'crawlerStartFn', {
67+
const crawlerStartFn = new PreBundledFunction(this, 'StartFn', {
6868
runtime: Runtime.PYTHON_3_9,
6969
codePath: 'synchronous-crawler/resources/lambdas',
70-
name: 'SynchronousCrawlerStartFn',
7170
layers: [PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer')],
7271
lambdaPolicyStatements: lambdaCRPolicy,
7372
handler: 'lambda.on_event',
@@ -76,10 +75,9 @@ export class SynchronousCrawler extends Construct {
7675
});
7776

7877
// AWS Lambda function for the AWS CDK Custom Resource responsible to wait for crawler completion
79-
const crawlerWaitFn = new PreBundledFunction(this, 'crawlerWaitFn', {
78+
const crawlerWaitFn = new PreBundledFunction(this, 'WaitFn', {
8079
runtime: Runtime.PYTHON_3_9,
8180
codePath: 'synchronous-crawler/resources/lambdas',
82-
name: 'SynchronousCrawlerWaitFn',
8381
layers: [PreBundledLayer.getOrCreate(scope, 'common/resources/lambdas/pre-bundled-layer')],
8482
lambdaPolicyStatements: lambdaCRPolicy,
8583
handler: 'lambda.is_complete',

core/test/e2e/batch-replayer.test.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import { Bucket } from 'aws-cdk-lib/aws-s3';
1111
import * as cdk from 'aws-cdk-lib';
1212
import { RemovalPolicy } from 'aws-cdk-lib';
13-
import { deployStack /*, destroyStack*/ } from './utils';
13+
import { deployStack , destroyStack } from './utils';
1414

1515
import { BatchReplayer } from '../../src/data-generator/batch-replayer';
1616
import { PreparedDataset } from '../../src/data-generator/prepared-dataset';
@@ -30,6 +30,11 @@ const batchReplayer = new BatchReplayer(stack, 'BatchReplay', {
3030
sinkBucket: sinkBucket,
3131
});
3232

33+
new BatchReplayer(stack, 'BatchReplay2', {
34+
dataset: PreparedDataset.RETAIL_1_GB_CUSTOMER,
35+
sinkBucket: sinkBucket,
36+
});
37+
3338
new cdk.CfnOutput(stack, 'DatasetName', {
3439
value: batchReplayer.dataset.tableName,
3540
exportName: 'DatasetName',

core/test/unit/cdk-nag/nag-batch-replayer.test.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -30,37 +30,37 @@ Aspects.of(batchReplayer).add(new AwsSolutionsChecks());
3030

3131
NagSuppressions.addResourceSuppressionsByPath(
3232
batchReplayerStack,
33-
'BatchReplayer/TestBatchReplayer/LambdaExecutionRolePolicyFindFilePathsFn/Resource',
33+
'BatchReplayer/TestBatchReplayer/LambdaExecutionRolePolicyTestBatchReplayerFindFilePath/Resource',
3434
[{ id: 'AwsSolutions-IAM5', reason: 'The IAM policy needs access to all objects in the source dataset' }],
3535
);
3636

3737
NagSuppressions.addResourceSuppressionsByPath(
3838
batchReplayerStack,
39-
'BatchReplayer/TestBatchReplayer/LogRetentionLambdaExecutionRolePolicyFindFilePathsFn/Resource',
39+
'BatchReplayer/TestBatchReplayer/LogRetentionLambdaExecutionRolePolicyTestBatchReplayerFindFilePath/Resource',
4040
[{ id: 'AwsSolutions-IAM5', reason: 'The Lambda execution role for log retention needs * access' }],
4141
);
4242

4343
NagSuppressions.addResourceSuppressionsByPath(
4444
batchReplayerStack,
45-
'BatchReplayer/TestBatchReplayer/LogRetentionLambdaExecutionRoleFindFilePathsFn/DefaultPolicy/Resource',
45+
'BatchReplayer/TestBatchReplayer/LogRetentionLambdaExecutionRoleTestBatchReplayerFindFilePath/DefaultPolicy/Resource',
4646
[{ id: 'AwsSolutions-IAM5', reason: 'The Lambda execution role for log retention needs * access' }],
4747
);
4848

4949
NagSuppressions.addResourceSuppressionsByPath(
5050
batchReplayerStack,
51-
'BatchReplayer/TestBatchReplayer/LambdaExecutionRolePolicyWriteInBatchFn/Resource',
51+
'BatchReplayer/TestBatchReplayer/LambdaExecutionRolePolicyTestBatchReplayerWriteInBatch/Resource',
5252
[{ id: 'AwsSolutions-IAM5', reason: 'The IAM policy needs access to all objects in the sink location' }],
5353
);
5454

5555
NagSuppressions.addResourceSuppressionsByPath(
5656
batchReplayerStack,
57-
'BatchReplayer/TestBatchReplayer/LambdaExecutionRoleWriteInBatchFn/DefaultPolicy/Resource',
57+
'BatchReplayer/TestBatchReplayer/LambdaExecutionRoleTestBatchReplayerWriteInBatch/DefaultPolicy/Resource',
5858
[{ id: 'AwsSolutions-IAM5', reason: 'The IAM policy needs access to all objects in the sink location' }],
5959
);
6060

6161
NagSuppressions.addResourceSuppressionsByPath(
6262
batchReplayerStack,
63-
'BatchReplayer/TestBatchReplayer/LogRetentionLambdaExecutionRolePolicyWriteInBatchFn/Resource',
63+
'BatchReplayer/TestBatchReplayer/LogRetentionLambdaExecutionRolePolicyTestBatchReplayerWriteInBatch/Resource',
6464
[{ id: 'AwsSolutions-IAM5', reason: 'The Lambda execution role for log retention needs * access' }],
6565
);
6666

0 commit comments

Comments
 (0)