Skip to content

Commit f48c237

Browse files
author
Florian Chazal
committed
feat: publish lib as Lambda Layer
1 parent f25f7bf commit f48c237

File tree

10 files changed

+260
-13
lines changed

10 files changed

+260
-13
lines changed

Diff for: .github/workflows/publish_layer.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ on:
1414
required: true
1515
# Automatic trigger after release
1616
workflow_run:
17-
workflows: ["release"]
17+
workflows: ["Make Release"]
1818
types:
1919
- completed
2020

Diff for: docs/index.md

+178
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,184 @@ Core utilities such as Tracer, Logger, Metrics, and Event Handler will be availa
2828

2929
## Installation
3030

31+
You can use Powertools through [AWS Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-layer) or install it as your dependency via NPM:
32+
33+
* **Lambda Layer**: [**arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:1**](#){: .copyMe}:clipboard:
34+
* **NPM**: **`npm install @aws-lambda-powertools/tracer @aws-lambda-powertools/metrics @aws-lambda-powertools/logger`**
35+
36+
???+ hint "Support this project by using Lambda Layers :heart:"
37+
Lambda Layers allow us to understand who uses this library in a non-intrusive way. This helps us justify and gain future investments for other Lambda Powertools languages.
38+
39+
When using Layers, you can add Lambda Powertools as a dev dependency to not impact the development process.
40+
41+
42+
### Lambda Layer
43+
44+
[Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html){target="_blank"} is a .zip file archive that can contain additional code, pre-packaged dependencies, data, or configuration files. Layers promote code sharing and separation of responsibilities so that you can iterate faster on writing business logic.
45+
46+
You can include Lambda Powertools Lambda Layer using [AWS Lambda Console](https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html#invocation-layers-using){target="_blank"}, or your preferred deployment framework.
47+
48+
??? note "Note: Expand to copy any regional Lambda Layer ARN"
49+
50+
| Region | Layer ARN
51+
|--------------------------- | ---------------------------
52+
| `us-east-1` | [arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
53+
| `us-east-2` | [arn:aws:lambda:us-east-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
54+
| `us-west-1` | [arn:aws:lambda:us-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
55+
| `us-west-2` | [arn:aws:lambda:us-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
56+
| `ap-south-1` | [arn:aws:lambda:ap-south-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
57+
| `ap-northeast-1` | [arn:aws:lambda:ap-northeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
58+
| `ap-northeast-2` | [arn:aws:lambda:ap-northeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
59+
| `ap-northeast-3` | [arn:aws:lambda:ap-northeast-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
60+
| `ap-southeast-1` | [arn:aws:lambda:ap-southeast-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
61+
| `ap-southeast-2` | [arn:aws:lambda:ap-southeast-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
62+
| `eu-central-1` | [arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
63+
| `eu-west-1` | [arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
64+
| `eu-west-2` | [arn:aws:lambda:eu-west-2:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
65+
| `eu-west-3` | [arn:aws:lambda:eu-west-3:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
66+
| `eu-north-1` | [arn:aws:lambda:eu-north-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
67+
| `ca-central-1` | [arn:aws:lambda:ca-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
68+
| `sa-east-1` | [arn:aws:lambda:sa-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1](#){: .copyMe}:clipboard:
69+
70+
??? question "Can't find our Lambda Layer for your preferred AWS region?"
71+
You can use our [CDK Layer Construct](https://github.com/aws-samples/cdk-lambda-powertools-python-layer){target="_blank"}, or NPM like you normally would for any other library.
72+
73+
Please do file a feature request with the region you'd want us to prioritize making our Lambda Layer available.
74+
75+
=== "SAM"
76+
77+
```yaml hl_lines="5"
78+
MyLambdaFunction:
79+
Type: AWS::Serverless::Function
80+
Properties:
81+
Layers:
82+
- !Sub arn:aws:lambda:${AWS::Region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:1
83+
```
84+
85+
=== "Serverless framework"
86+
87+
```yaml hl_lines="5"
88+
functions:
89+
hello:
90+
handler: lambda_function.lambda_handler
91+
layers:
92+
- arn:aws:lambda:${aws:region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:1
93+
```
94+
95+
=== "CDK"
96+
97+
```typescript hl_lines="11 16"
98+
import * as cdk from 'aws-cdk-lib';
99+
import { Construct } from 'constructs';
100+
import * as lambda from 'aws-cdk-lib/aws-lambda';
101+
export class SampleFunctionWithLayer extends Construct {
102+
constructor(scope: Construct, id: string) {
103+
super(scope, id);
104+
// Create a Layer with AWS Lambda Powertools for TypeScript
105+
const powertoolsLayer = lambda.LayerVersion.fromLayerVersionArn(
106+
this,
107+
'PowertoolsLayer',
108+
`arn:aws:lambda:${cdk.Stack.of(this).region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:1`
109+
);
110+
new lambda.Function(this, 'Function', {
111+
runtime: lambda.Runtime.NODEJS_16_X,
112+
// Add the Layer to a Lambda function
113+
layers: [powertoolsLayer],
114+
code: lambda.Code.fromInline(`
115+
const { Logger } = require('@aws-lambda-powertools/logger');
116+
const { Metrics } = require('@aws-lambda-powertools/metrics');
117+
const { Tracer } = require('@aws-lambda-powertools/tracer');
118+
const logger = new Logger({logLevel: 'DEBUG'});
119+
const metrics = new Metrics();
120+
const tracer = new Tracer();
121+
exports.handler = function(event, ctx) {
122+
logger.debug("Hello World!");
123+
}`),
124+
handler: 'index.handler',
125+
});
126+
}
127+
}
128+
```
129+
130+
=== "Terraform"
131+
132+
```terraform hl_lines="9 38"
133+
terraform {
134+
required_version = "~> 1.0.5"
135+
required_providers {
136+
aws = "~> 3.50.0"
137+
}
138+
}
139+
provider "aws" {
140+
region = "{region}"
141+
}
142+
resource "aws_iam_role" "iam_for_lambda" {
143+
name = "iam_for_lambda"
144+
assume_role_policy = <<EOF
145+
{
146+
"Version": "2012-10-17",
147+
"Statement": [
148+
{
149+
"Action": "sts:AssumeRole",
150+
"Principal": {
151+
"Service": "lambda.amazonaws.com"
152+
},
153+
"Effect": "Allow"
154+
}
155+
]
156+
}
157+
EOF
158+
}
159+
resource "aws_lambda_function" "test_lambda" {
160+
filename = "lambda_function_payload.zip"
161+
function_name = "lambda_function_name"
162+
role = aws_iam_role.iam_for_lambda.arn
163+
handler = "index.test"
164+
runtime = "nodejs16.x"
165+
layers = ["arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:1"]
166+
source_code_hash = filebase64sha256("lambda_function_payload.zip")
167+
}
168+
```
169+
170+
=== "Amplify"
171+
172+
```zsh
173+
# Create a new one with the layer
174+
❯ amplify add function
175+
? Select which capability you want to add: Lambda function (serverless function)
176+
? Provide an AWS Lambda function name: <NAME-OF-FUNCTION>
177+
? Choose the runtime that you want to use: NodeJS
178+
? Do you want to configure advanced settings? Yes
179+
...
180+
? Do you want to enable Lambda layers for this function? Yes
181+
? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1
182+
❯ amplify push -y
183+
# Updating an existing function and add the layer
184+
❯ amplify update function
185+
? Select the Lambda function you want to update test2
186+
General information
187+
- Name: <NAME-OF-FUNCTION>
188+
? Which setting do you want to update? Lambda layers configuration
189+
? Do you want to enable Lambda layers for this function? Yes
190+
? Enter up to 5 existing Lambda layer ARNs (comma-separated): arn:aws:lambda:eu-central-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1
191+
? Do you want to edit the local lambda function now? No
192+
```
193+
194+
=== "Get the Layer .zip contents"
195+
Change `{region}` to your AWS region, e.g. `eu-west-1`
196+
197+
```bash title="AWS CLI"
198+
aws lambda get-layer-version-by-arn --arn arn:aws:lambda:{region}:094274105915:layer:AWSLambdaPowertoolsTypeScript:1 --region {region}
199+
```
200+
201+
The pre-signed URL to download this Lambda Layer will be within `Location` key.
202+
203+
???+ warning "Warning: Limitations"
204+
205+
Container Image deployment (OCI) or inline Lambda functions do not support Lambda Layers.
206+
207+
### NPM Modules
208+
31209
The AWS Lambda Powertools for TypeScript utilities (which from here will be referred as Powertools) follow a modular approach, similar to the official [AWS SDK v3 for JavaScript](https://github.com/aws/aws-sdk-js-v3).
32210
Each TypeScript utility is installed as standalone NPM package.
33211

Diff for: examples/cdk/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The example functions, located in the `src` folder, are invoked automatically, t
99
## Deploying the stack
1010

1111
* Navigate to this location of the repo in your terminal (`examples/cdk`)
12-
* `npm install`
12+
* `npm ci`
1313
* `npm run cdk deploy --all --profile <YOUR_AWS_PROFILE>`
1414

1515
Note: Prior to deploying you may need to run `cdk bootstrap aws://<YOU_AWS_ACCOUNT_ID>/<AWS_REGION> --profile <YOUR_AWS_PROFILE>` if you have not already bootstrapped your account for CDK.

Diff for: examples/cdk/package-lock.json

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: examples/cdk/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"devDependencies": {
2727
"@types/jest": "^27.4.0",
2828
"@types/node": "18.0.0",
29-
"aws-cdk": "^2.0.0",
29+
"aws-cdk": "2.27.0",
3030
"esbuild": "^0.14.23",
3131
"jest": "^27.5.1",
3232
"ts-jest": "^27.1.4",

Diff for: examples/cdk/src/example-layer.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { custom_resources, aws_iam } from 'aws-cdk-lib';
2+
import { Events } from '@aws-lambda-powertools/commons';
3+
import { Construct } from 'constructs';
4+
import { Code, Function, FunctionProps, LayerVersion } from 'aws-cdk-lib/aws-lambda';
5+
import { Tracing, Runtime } from 'aws-cdk-lib/aws-lambda';
6+
import path from 'path';
7+
8+
interface LayeredFunctionProps {
9+
readonly functionName: string
10+
readonly tracingActive?: boolean
11+
readonly invocations?: number
12+
readonly fnProps?: Partial<FunctionProps>
13+
}
14+
15+
class LayeredFunction extends Construct {
16+
17+
public constructor(scope: Construct, id: string, props: LayeredFunctionProps) {
18+
super(scope, id);
19+
20+
const { functionName, tracingActive, invocations, fnProps } = Object.assign({
21+
tracingActive: false,
22+
invocations: 2
23+
}, props);
24+
25+
const fn = new Function(this, functionName, {
26+
tracing: tracingActive ? Tracing.ACTIVE : Tracing.DISABLED,
27+
runtime: Runtime.NODEJS_16_X,
28+
code: Code.fromAsset(path.join(__dirname, './')),
29+
handler: 'example-function.MyFunction.handler',
30+
layers: [
31+
LayerVersion.fromLayerVersionArn(this, 'AWSLambdaPowertoolsTypeScript', 'arn:aws:lambda:eu-west-1:094274105915:layer:AWSLambdaPowertoolsTypeScript:1')
32+
],
33+
...fnProps
34+
});
35+
36+
for (let i = 0; i < invocations; i++) {
37+
new custom_resources.AwsCustomResource(this, `Invoke-${functionName}-${i}`, {
38+
onUpdate: {
39+
service: 'Lambda',
40+
action: 'invoke',
41+
physicalResourceId: custom_resources.PhysicalResourceId.of(`${functionName}-${i}`),
42+
parameters: {
43+
FunctionName: fn.functionName,
44+
InvocationType: 'RequestResponse',
45+
Payload: JSON.stringify(Events.Custom.CustomEvent),
46+
}
47+
},
48+
policy: custom_resources.AwsCustomResourcePolicy.fromStatements([
49+
new aws_iam.PolicyStatement({
50+
effect: aws_iam.Effect.ALLOW,
51+
resources: [
52+
fn.functionArn,
53+
],
54+
actions: ['lambda:InvokeFunction'],
55+
}),
56+
]),
57+
});
58+
}
59+
}
60+
}
61+
62+
export {
63+
LayeredFunction
64+
};

Diff for: examples/cdk/src/example-stack.ts

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Stack, StackProps } from 'aws-cdk-lib';
22
import { Construct } from 'constructs';
3+
import { LayeredFunction } from './example-layer';
34
import { ExampleFunction } from './example-function';
45

56
export class CdkAppStack extends Stack {
@@ -66,5 +67,9 @@ export class CdkAppStack extends Stack {
6667
tracingActive: true,
6768
});
6869

70+
new LayeredFunction(this, 'MyLayeredFunction', {
71+
functionName: 'MyLayeredFunction',
72+
tracingActive: true,
73+
});
6974
}
7075
}

Diff for: examples/cdk/tests/cdk-app.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ import * as CdkApp from '../src/example-stack';
55
test('CDK code synthesize', () => {
66
const app = new cdk.App();
77
const stack = new CdkApp.CdkAppStack(app, 'MyTestStack');
8-
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 13);
8+
Template.fromStack(stack).resourceCountIs('AWS::Lambda::Function', 14);
99
});

Diff for: layer-publisher/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"jest": "^26.4.2",
2525
"ts-jest": "^26.2.0",
2626
"ts-node": "^9.0.0",
27-
"typescript": "~3.9.7"
27+
"typescript": "4.8.3"
2828
},
2929
"dependencies": {
3030
"aws-cdk-lib": "2.25.0",

Diff for: layer-publisher/tests/unit/__snapshots__/layer-publisher.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Object {
3232
"S3Bucket": Object {
3333
"Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}",
3434
},
35-
"S3Key": "23ee10788554a52cf42e2930c2fb70b2d0260807f69479e9cef221a77d0cbc28.zip",
35+
"S3Key": "6eba0de0afc84e169557e039f71f823118dc01c239decea38379b17d3edee2d3.zip",
3636
},
3737
"Description": "Lambda Powertools for TypeScript version 1.0.1",
3838
"LayerName": "AWSLambdaPowertoolsTypeScript",

0 commit comments

Comments
 (0)