Skip to content
This repository was archived by the owner on Sep 8, 2022. It is now read-only.

feat: Generalize the construct to be usable by other PowerTools supported languages #52

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .projenrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const project = new awscdk.AwsCdkConstructLibrary({
authorUrl: 'https://aws.amazon.com',
authorOrganization: true,
keywords: ['aws', 'cdk', 'powertools', 'python', 'layer', 'lambda', 'devax'],
cdkVersion: '2.2.0',
cdkVersion: '2.24.1',
defaultReleaseBranch: 'main',
majorVersion: 2,
name: 'cdk-lambda-powertools-python-layer',
Expand Down
21 changes: 20 additions & 1 deletion API.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,15 @@ new LambdaPowertoolsLayer(scope: Construct, id: string, props?: PowertoolsLayerP
```typescript
import { LambdaPowertoolsLayer } from 'cdk-lambda-powertools-python-layer'

LambdaPowertoolsLayer.constructBuildArgs(includeExtras?: boolean, version?: string)
LambdaPowertoolsLayer.constructBuildArgs(runtimeFamily: RuntimeFamily, includeExtras?: boolean, version?: string)
```

###### `runtimeFamily`<sup>Required</sup> <a name="cdk-lambda-powertools-python-layer.LambdaPowertoolsLayer.parameter.runtimeFamily" id="cdklambdapowertoolspythonlayerlambdapowertoolslayerparameterruntimefamily"></a>

- *Type:* [`aws-cdk-lib.aws_lambda.RuntimeFamily`](#aws-cdk-lib.aws_lambda.RuntimeFamily)

---

###### `includeExtras`<sup>Optional</sup> <a name="cdk-lambda-powertools-python-layer.LambdaPowertoolsLayer.parameter.includeExtras" id="cdklambdapowertoolspythonlayerlambdapowertoolslayerparameterincludeextras"></a>

- *Type:* `boolean`
Expand Down Expand Up @@ -91,6 +97,7 @@ const powertoolsLayerProps: PowertoolsLayerProps = { ... }
| --- | --- | --- |
| [`includeExtras`](#cdklambdapowertoolspythonlayerpowertoolslayerpropspropertyincludeextras) | `boolean` | A flag for the pydantic extras dependency, used for parsing. |
| [`layerVersionName`](#cdklambdapowertoolspythonlayerpowertoolslayerpropspropertylayerversionname) | `string` | the name of the layer, will be randomised if empty. |
| [`runtimeFamily`](#cdklambdapowertoolspythonlayerpowertoolslayerpropspropertyruntimefamily) | [`aws-cdk-lib.aws_lambda.RuntimeFamily`](#aws-cdk-lib.aws_lambda.RuntimeFamily) | the runtime of the layer. |
| [`version`](#cdklambdapowertoolspythonlayerpowertoolslayerpropspropertyversion) | `string` | The powertools package version from pypi repository. |

---
Expand Down Expand Up @@ -121,6 +128,18 @@ the name of the layer, will be randomised if empty.

---

##### `runtimeFamily`<sup>Optional</sup> <a name="cdk-lambda-powertools-python-layer.PowertoolsLayerProps.property.runtimeFamily" id="cdklambdapowertoolspythonlayerpowertoolslayerpropspropertyruntimefamily"></a>

```typescript
public readonly runtimeFamily: RuntimeFamily;
```

- *Type:* [`aws-cdk-lib.aws_lambda.RuntimeFamily`](#aws-cdk-lib.aws_lambda.RuntimeFamily)

the runtime of the layer.

---

##### `version`<sup>Optional</sup> <a name="cdk-lambda-powertools-python-layer.PowertoolsLayerProps.property.version" id="cdklambdapowertoolspythonlayerpowertoolslayerpropspropertyversion"></a>

```typescript
Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions layer/TypeScript/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM public.ecr.aws/lambda/nodejs:16



ARG PACKAGE_SUFFIX=''

USER root
WORKDIR /tmp

RUN yum update -y && yum install -y zip unzip wget tar gzip

RUN npm install --prefix /asset/nodejs @aws-lambda-powertools/metrics$PACKAGE_SUFFIX @aws-lambda-powertools/tracer$PACKAGE_SUFFIX @aws-lambda-powertools/logger$PACKAGE_SUFFIX
4 changes: 2 additions & 2 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 68 additions & 16 deletions src/lambda-powertools-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ export interface PowertoolsLayerProps {
* the name of the layer, will be randomised if empty
*/
readonly layerVersionName?: string;

/**
* the runtime of the layer
*/
readonly runtimeFamily?: lambda.RuntimeFamily;
}

/**
* Defines a new Lambda Layer with Powertools for python library.
*/
export class LambdaPowertoolsLayer extends lambda.LayerVersion {


/**
* creates build argument for the Dockerfile.
* There are multiple combinations between version and extras package that results in different suffix for the installation.
Expand All @@ -36,35 +39,84 @@ export class LambdaPowertoolsLayer extends lambda.LayerVersion {
* For example, if we set extras=true and version=1.22.0 we get '[pydantic]==1.22.0'.
*
*/
static constructBuildArgs(includeExtras: boolean | undefined, version: string | undefined): string {
static constructBuildArgs(
runtimeFamily: lambda.RuntimeFamily,
includeExtras: boolean | undefined,
version: string | undefined,
): string {
let suffix = '';
if (includeExtras) {
suffix = '[pydantic]';
}
if (version) {
suffix = `${suffix}==${version}`;
switch (runtimeFamily) {
case lambda.RuntimeFamily.PYTHON:
if (includeExtras) {
suffix = '[pydantic]';
}
if (version) {
suffix = `${suffix}==${version}`;
}
break;
case lambda.RuntimeFamily.NODEJS:
if (version) {
suffix = `@${version}`;
}
break;
default:
break;
}
return suffix;
}


constructor(scope: Construct, id: string, props?: PowertoolsLayerProps) {
const runtimeFamily = props?.runtimeFamily ?? lambda.RuntimeFamily.PYTHON;
const languageName = getLanguageNameFromRuntimeFamily(runtimeFamily);
const dockerFilePath = path.join(__dirname, `../layer/${languageName}`);
console.log(`path ${dockerFilePath}`);
super(scope, id, {
code: lambda.Code.fromDockerBuild(path.join(__dirname, '../layer'), {
code: lambda.Code.fromDockerBuild(dockerFilePath, {
buildArgs: {
PACKAGE_SUFFIX: LambdaPowertoolsLayer.constructBuildArgs(props?.includeExtras, props?.version),
PACKAGE_SUFFIX: LambdaPowertoolsLayer.constructBuildArgs(
runtimeFamily,
props?.includeExtras,
props?.version,
),
},
}),
layerVersionName: props?.layerVersionName ? props?.layerVersionName : undefined,
license: 'MIT-0',
compatibleRuntimes: [
compatibleRuntimes: getRuntimesFromRuntimeFamily(runtimeFamily),
description: `Lambda Powertools for ${languageName}${
props?.includeExtras ? ' with Pydantic' : ''
} ${props?.version ? `version ${props?.version}` : 'latest version'}`.trim(),
});
}
}

function getRuntimesFromRuntimeFamily(runtimeFamily: lambda.RuntimeFamily): lambda.Runtime[] | undefined {
switch (runtimeFamily) {
case lambda.RuntimeFamily.PYTHON:
return [
lambda.Runtime.PYTHON_3_6,
lambda.Runtime.PYTHON_3_7,
lambda.Runtime.PYTHON_3_8,
lambda.Runtime.PYTHON_3_9,
],
description: `Lambda Powertools for Python${props?.includeExtras ? ' with Pydantic' : ''} ${props?.version ? `version ${props.version}` : 'latest version'}`.trim(),
});
};
];
case lambda.RuntimeFamily.NODEJS:
return [
lambda.Runtime.NODEJS_12_X,
lambda.Runtime.NODEJS_14_X,
lambda.Runtime.NODEJS_16_X,
];
default:
return [];
}
}

function getLanguageNameFromRuntimeFamily(runtimeFamily: lambda.RuntimeFamily): string {
switch (runtimeFamily) {
case lambda.RuntimeFamily.PYTHON:
return 'Python';
case lambda.RuntimeFamily.NODEJS:
return 'TypeScript';
default:
return 'Unknown';
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Stack } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { LambdaPowertoolsLayer } from '../lib';
import { RuntimeFamily } from 'aws-cdk-lib/aws-lambda';
import { LambdaPowertoolsLayer } from '../src';


describe('with no configuration the construct', () => {
Expand Down Expand Up @@ -91,25 +92,25 @@ describe('with version configuration the construct', () => {

describe('construct build args for Dockerfile', () => {
test('returns pydantic and version', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(true, '1.21.0');
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, true, '1.21.0');

expect(args).toEqual('[pydantic]==1.21.0');
});

test('returns only pydantic when no version provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(true, undefined);
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, true, undefined);

expect(args).toEqual('[pydantic]');
});

test('returns only version when no extras flag provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(undefined, '1.11.0');
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, undefined, '1.11.0');

expect(args).toEqual('==1.11.0');
});

test('returns empty when no version and extras provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(undefined, undefined);
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, undefined, undefined);

expect(args).toEqual('');
});
Expand Down
85 changes: 85 additions & 0 deletions test/lambda-powertools-typescript-layer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Stack } from 'aws-cdk-lib';
import { Template } from 'aws-cdk-lib/assertions';
import { RuntimeFamily } from 'aws-cdk-lib/aws-lambda';
import { LambdaPowertoolsLayer } from '../src';


describe('with minimal configuration the construct', () => {
const stack = new Stack();
new LambdaPowertoolsLayer(stack, 'PowertoolsLayer', {
runtimeFamily: RuntimeFamily.NODEJS,
});
const template = Template.fromStack(stack);
test('synthesizes successfully', () => {
template.hasResourceProperties('AWS::Lambda::LayerVersion', {
Description: 'Lambda Powertools for TypeScript latest version',
});
});

test('has license set to MIT-0', () => {
template.hasResourceProperties('AWS::Lambda::LayerVersion', {
LicenseInfo: 'MIT-0',
});
});

test('matches the nodejs runtimes', () => {
template.hasResourceProperties('AWS::Lambda::LayerVersion', {
CompatibleRuntimes: [
'nodejs12.x',
'nodejs14.x',
'nodejs16.x',
],
});
});
});

describe('for layerVersionName configuration the construct', () => {
test('synthisizes to a layer with provided name', () => {
const stack = new Stack();
new LambdaPowertoolsLayer(stack, 'PowertoolsLayer', {
layerVersionName: 'mySpecialName',
});

Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
LayerName: 'mySpecialName',
});
});
});

describe('with version configuration the construct', () => {
test('synthesizes to a layer with specific valid version', () => {
const stack = new Stack();
const version = '0.9.0';
new LambdaPowertoolsLayer(stack, 'PowertoolsLayer', {
runtimeFamily: RuntimeFamily.NODEJS,
version: version,
});


Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
Description: `Lambda Powertools for TypeScript version ${version}`,
});
});

test('fails with invalid version', () => {
const stack = new Stack();
expect(() => new LambdaPowertoolsLayer(stack, 'PowertoolsLayerBadVersion', {
runtimeFamily: RuntimeFamily.NODEJS,
version: '12.222.21123',
})).toThrow(/docker exited with status 1/);
});


test('returns version with @ when provided provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.NODEJS, undefined, '0.9.0');

expect(args).toEqual('@0.9.0');
});

test('returns empty when no version provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.NODEJS, undefined, undefined);

expect(args).toEqual('');
});

});
Loading