Skip to content

Commit 1a9c30e

Browse files
authored
feat: implement code generated handler framework (#28251)
This PR introduces an internal handler framework used to code generate constructs that extend a lambda `Function`, lambda `SingletonFunction`, or core `CustomResourceProvider` construct and prohibit the user from directly configuring the `handler`, `runtime`, `code`, and `codeDirectory` properties. In doing this, we are able to establish best practices, runtime enforcement, and consistency across all handlers we build and vend within the aws-cdk. As expected, no integ tests were changed as a result of this PR. To verify that the code generated custom resource providers are working correctly I force ran three integ tests all targeted at an individual custom resource provider: 1. integ.global.ts to test replica provider and the code generated construct extending `Function` 2. integ.bucket-auto-delete-objects.ts to test auto delete objects provider and the code generated construct extending `CustomResourceProvider` 3. integ.aws-api.ts to test aws api provider and the code generated construct `SingletonFunction` All of these integ tests passed successfully. Closes #27303 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 21a0fa6 commit 1a9c30e

File tree

44 files changed

+1855
-619
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1855
-619
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# CDK Handler Framework
2+
3+
The CDK handler framework is an internal framework used to code generate constructs that extend a lambda `Function`, lambda `SingletonFunction`, or core `CustomResourceProvider` construct and prohibit the user from directly configuring the `handler`, `runtime`, `code`, and `codeDirectory` properties. In doing this, we are able to establish best practices, runtime enforcement, and consistency across all handlers we build and vend within the aws-cdk.
4+
5+
## CDK Handler Framework Concepts
6+
7+
This framework allows for the creation of three component types:
8+
1. `ComponentType.FUNCTION` - This is a wrapper around the lambda `Function` construct. It offers the same behavior and performance as a lambda `Function`, but it restricts the consumer from configuring the `handler`, `runtime`, and `code` properties.
9+
2. `ComponentType.SINGLETON_FUNCTION` - This is a wrapper around the lambda `SingletonFunction` construct. It offers the same behavior and performance as a lambda `SingletonFunction`, but it restricts the consumer from configuring the `handler`, `runtime`, and `code` properties.
10+
3. `ComponentType.CUSTOM_RESOURCE_PROVIDER` - This is a wrapper around the core `CustomResourceProvider` construct. It offers the same behavior and performance as a `CustomResourceProvider` and can be instantiated via the `getOrCreate` or `getOrCreateProvider` methods. This component restricts the consumer from configuring the `runtime` and `codeDirectory` properties.
11+
12+
Code generating one of these three component types requires adding the component properties to the [config](./config.ts) file by providing `ComponentProps`. The `ComponentProps` are responsible for code generating the specified `ComponentType` with the `handler`, `runtime`, `code`, and `codeDirectory` properties set internally. `ComponentProps` includes the following properties:
13+
- `type` - the framework component type to generate.
14+
- `sourceCode` - the source code that will be excuted by the framework component.
15+
- `runtime` - the runtime that is compatible with the framework component's source code. This is an optional property with a default node runtime maintained by the framework.
16+
- `handler` - the name of the method with the source code that the framework component will call. This is an optional property and the default is `index.handler`.
17+
- `minifyAndBundle` - whether the source code should be minified and bundled. This an optional property and the default is `true`. This should only be set to `false` for python files or for typescript/javascript files with a require import.
18+
19+
The [config](./config.ts) file is structured with the top level mapping to an aws-cdk module, i.e., aws-s3, aws-dynamodb, etc. Each service can contain one or more component modules. Component modules are containers for handler framework components and will be rendered as a code generated file. Each component module can contain one or more `ComponentProps` objects. The following example shows a more structural breakdown of how the [config](./config.ts) file is configured:
20+
21+
```ts
22+
const config = {
23+
'aws-s3': { // the aws-cdk-lib module
24+
'replica-provider': [ // the component module
25+
// handler framework component defined as a `ComponentProps` object
26+
{
27+
// the handler framework component type
28+
type: ComponentType.FUNCTION,
29+
// the source code that the component will use
30+
sourceCode: path.resolve(__dirname, '..', 'aws-dynamodb', 'replica-handler', 'index.ts'),
31+
// the handler in the source code that the component will execute
32+
handler: 'index.onEventHandler',
33+
},
34+
],
35+
},
36+
'aws-stepfunctions-tasks': {
37+
// contains multiple component modules
38+
'eval-nodejs-provider': [
39+
{
40+
type: ComponentType.SINGLETON_FUNCTION,
41+
sourceCode: path.resolve(__dirname, '..', 'aws-stepfunctions-tasks', 'eval-nodejs-handler', 'index.ts'),
42+
},
43+
],
44+
'role-policy-provider': [
45+
{
46+
type: ComponentType.SINGLETON_FUNCTION,
47+
sourceCode: path.resolve(__dirname, '..', 'aws-stepfunctions-tasks', 'role-policy-handler', 'index.py'),
48+
runtime: Runtime.PYTHON_3_9,
49+
// prevent minify and bundle since the source code is a python file
50+
minifyAndBundle: false,
51+
},
52+
],
53+
},
54+
};
55+
```
56+
57+
Code generation for the component modules is triggered when this package - `@aws-cdk/custom-resource-handlers` - is built. Importantly, this framework is also responsible for minifying and bundling the custom resource providers' source code and dependencies. A flag named `minifyAndBundle` can be configured as part of the `ComponentProps` to prevent minifying and bundling the source code for a specific provider. This flag is only needed for python files or for typescript/javascript files containing require imports.
58+
59+
Once built, all generated code and bundled source code will be written to `@aws-cdk/custom-resource-handlers/dist`. The top level field in the [config](./config.ts) file defining individual aws-cdk modules will be used to create specific directories within `@aws-cdk/custom-resource-handlers/dist` and each component module will be a separate code generated file within these directories named `<component-module>.generated.ts`. As an example, the sample [config](./config.ts) file above would create the following file structure:
60+
61+
|--- @aws-cdk
62+
| |--- custom-resource-handlers
63+
| | |--- dist
64+
| | | |--- aws-s3
65+
| | | | |--- replica-handler
66+
| | | | | |--- index.js
67+
| | | | |--- replica-provider.generated.ts
68+
| | | |--- aws-stepfunctions-tasks
69+
| | | | |--- eval-nodejs-handler
70+
| | | | | |--- index.js
71+
| | | | |--- role-policy-handler
72+
| | | | | |--- index.py
73+
| | | | |--- eval-nodejs-provider.generated.ts
74+
| | | | |--- role-policy-provider.generated.ts
75+
76+
The code generated handler framework components are consumable from `aws-cdk-lib/custom-resource-handlers/dist` once `aws-cdk-lib` is built. The file structure of `aws-cdk-lib/custom-resource-handlers/dist` will have the same structure as `@aws-cdk/custom-resource-handlers/dist` with the exception of `core`. To prevent circular dependencies, all handler framework components defined in `core`and any associated source code will be consumable from `aws-cdk-lib/core/dist/core`.
77+
78+
## Creating a Handler Framework Component
79+
80+
Creating a new handler framework component involves three steps:
81+
1. Add the source code to `@aws-cdk/custom-resource-handlers/lib/<aws-cdk-lib-module>`
82+
2. Update the [config](./config.ts) file by specifying all required `ComponentProps`.
83+
3. At this point you can directly build `@aws-cdk/custom-resource-handlers` with `yarn build` to view the generated component in `@aws-cdk/custom-resource-handlers/dist`. Alternatively, you can build `aws-cdk-lib` with `npx lerna run build --scope=aws-cdk-lib --skip-nx-cache` to make the generated component available for use within `aws-cdk-lib`

0 commit comments

Comments
 (0)