Skip to content

Commit

Permalink
feat(aws-lambda): improvements to the code and runtime APIs (#945)
Browse files Browse the repository at this point in the history
* Simplify usage of assets for Lambda code. Instead of `Code.directory` and `Code.file`, just use `Code.asset(path)` and we will determine if this is a directory.
* If `Code.asset` (or the deprecated `Code.file`) references a non-zip file, an error will be thrown.
* Simplify `lambda.Runtime` by deleting the interfaces `InlinableRuntime` and `InlinableJavaScriptRuntime`, which fixes #902 and fixes #188 
* Remove `lambda.InlineJavaScriptLambda`.
* Remove `lambda.Runtime.NodeJS43Edge` which fixes #947 
* Add inlining support for NodeJS 8.10 (fixes #947)
* No need to provide read permissions for asset (fixes #664)

BREAKING CHANGE: The construct `lambda.InlineJavaScriptLambda` is no longer supported. Use `lambda.Code.inline` instead; `lambda.Runtime.NodeJS43Edge` runtime is removed. CloudFront docs [stipulate](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-lambda-function-configuration) that you should use node6.10 or node8.10. It is always possible to use any value by instantiating a `lambda.Runtime` object.
  • Loading branch information
Elad Ben-Israel authored Oct 17, 2018
1 parent e790db5 commit 36f29b6
Show file tree
Hide file tree
Showing 17 changed files with 292 additions and 699 deletions.
21 changes: 9 additions & 12 deletions packages/@aws-cdk/aws-lambda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import lambda = require('@aws-cdk/aws-lambda');
const fn = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NodeJS810,
handler: 'index.handler',
code: lambda.Code.inline('exports.handler = function(event, ctx, cb) { return cb(null, "hi"); }'),
code: lambda.Code.asset('./lambda-handler'),
});
```

Expand All @@ -17,18 +17,15 @@ const fn = new lambda.Function(this, 'MyFunction', {
The `lambda.Code` class includes static convenience methods for various types of
runtime code.

* `lambda.Code.bucket(bucket, key[, objectVersion])` - specify an S3 object that
contains the archive of your runtime code.
* `lambda.Code.bucket(bucket, key[, objectVersion])` - specify an S3 object
that contains the archive of your runtime code.
* `lambda.Code.inline(code)` - inline the handle code as a string. This is
limited to 4KB. The class `InlineJavaScriptLambda` can be used to simplify
inlining JavaScript functions.
* `lambda.Code.directory(directory)` - specify a directory in the local filesystem
which will be zipped and uploaded to S3 before deployment.
* `lambda.Code.file(path)` - specify a file to be used for Lambda code. This can
be, for example a JAR or a ZIP file, based on the runtime used.

The following example shows how to define a Python function and deploy the code from the
local directory `my-lambda-handler` to it:
limited to 4KB.
* `lambda.Code.asset(path)` - specify a directory or a .zip file in the local
filesystem which will be zipped and uploaded to S3 before deployment.

The following example shows how to define a Python function and deploy the code
from the local directory `my-lambda-handler` to it:

[Example of Lambda Code from Local Assets](test/integ.assets.lit.ts)

Expand Down
34 changes: 29 additions & 5 deletions packages/@aws-cdk/aws-lambda/lib/code.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import assets = require('@aws-cdk/assets');
import s3 = require('@aws-cdk/aws-s3');
import fs = require('fs');
import { Function as Func } from './lambda';
import { cloudformation } from './lambda.generated';

Expand All @@ -22,10 +23,19 @@ export abstract class Code {
return new InlineCode(code);
}

/**
* Loads the function code from a local disk asset.
* @param path Either a directory with the Lambda code bundle or a .zip file
*/
public static asset(path: string) {
return new AssetCode(path);
}

/**
* @returns Zip archives the contents of a directory on disk and uses this
* as the lambda handler's code.
* @param directoryToZip The directory to zip
* @deprecated use `lambda.Code.asset(path)` (no need to specify if it's a file or a directory)
*/
public static directory(directoryToZip: string) {
return new AssetCode(directoryToZip, assets.AssetPackaging.ZipDirectory);
Expand All @@ -34,6 +44,7 @@ export abstract class Code {
/**
* @returns Uses a file on disk as a lambda handler's code.
* @param filePath The file path
* @deprecated use `lambda.Code.asset(path)` (no need to specify if it's a file or a directory)
*/
public static file(filePath: string) {
return new AssetCode(filePath, assets.AssetPackaging.File);
Expand Down Expand Up @@ -108,16 +119,27 @@ export class InlineCode extends Code {
* Lambda code from a local directory.
*/
export class AssetCode extends Code {
/**
* The asset packaging.
*/
public readonly packaging: assets.AssetPackaging;

private asset?: assets.Asset;

/**
* @param path The path to the asset file or directory.
* @param packaging The asset packaging format
* @param packaging The asset packaging format (optional, determined automatically)
*/
constructor(
private readonly path: string,
private readonly packaging: assets.AssetPackaging) {
constructor(public readonly path: string, packaging?: assets.AssetPackaging) {
super();

if (packaging !== undefined) {
this.packaging = packaging;
} else {
this.packaging = fs.lstatSync(path).isDirectory()
? assets.AssetPackaging.ZipDirectory
: assets.AssetPackaging.File;
}
}

public bind(lambda: Func) {
Expand All @@ -126,7 +148,9 @@ export class AssetCode extends Code {
packaging: this.packaging
});

this.asset.grantRead(lambda.role);
if (!this.asset.isZipArchive) {
throw new Error(`Asset must be a .zip file or a directory (${this.path})`);
}
}

public toJSON(): cloudformation.FunctionResource.CodeProperty {
Expand Down
1 change: 0 additions & 1 deletion packages/@aws-cdk/aws-lambda/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export * from './permission';
export * from './pipeline-action';
export * from './runtime';
export * from './code';
export * from './inline';
export * from './lambda-version';
export * from './singleton-lambda';

Expand Down
129 changes: 0 additions & 129 deletions packages/@aws-cdk/aws-lambda/lib/inline.ts

This file was deleted.

77 changes: 39 additions & 38 deletions packages/@aws-cdk/aws-lambda/lib/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,59 @@ export interface LambdaRuntimeProps {
* Whether the ``ZipFile`` (aka inline code) property can be used with this runtime.
* @default false
*/
readonly supportsInlineCode?: boolean;
supportsInlineCode?: boolean;
}

export enum RuntimeFamily {
NodeJS,
Java,
Python,
DotNetCore,
Go
}

/**
* Lambda function runtime environment.
*
* If you need to use a runtime name that doesn't exist as a static member, you
* can instantiate a `Runtime` object, e.g: `new Runtime('nodejs99.99')`.
*/
export class Runtime implements InlinableRuntime, InlinableJavaScriptRuntime {
/* tslint:disable variable-name */
public static readonly NodeJS = new Runtime('nodejs', { supportsInlineCode: true }) as InlinableJavaScriptRuntime;
// Using ``as InlinableLambdaRuntime`` because that class cannot be defined just yet
public static readonly NodeJS43 = new Runtime('nodejs4.3', { supportsInlineCode: true }) as InlinableJavaScriptRuntime;
public static readonly NodeJS43Edge = new Runtime('nodejs4.3-edge');
// Using ``as InlinableLambdaRuntime`` because that class cannot be defined just yet
public static readonly NodeJS610 = new Runtime('nodejs6.10', { supportsInlineCode: true }) as InlinableJavaScriptRuntime;
public static readonly NodeJS810 = new Runtime('nodejs8.10');
public static readonly Java8 = new Runtime('java8');
// Using ``as InlinableLambdaRuntime`` because that class cannot be defined just yet
public static readonly Python27 = new Runtime('python2.7', { supportsInlineCode: true }) as InlinableRuntime;
// Using ``as InlinableLambdaRuntime`` because that class cannot be defined just yet
public static readonly Python36 = new Runtime('python3.6', { supportsInlineCode: true }) as InlinableRuntime;
public static readonly DotNetCore1 = new Runtime('dotnetcore1.0');
public static readonly DotNetCore2 = new Runtime('dotnetcore2.0');
public static readonly DotNetCore21 = new Runtime('dotnetcore2.1');
public static readonly Go1x = new Runtime('go1.x');
/* tslint:enable variable-name */
export class Runtime {
public static readonly NodeJS = new Runtime('nodejs', RuntimeFamily.NodeJS, { supportsInlineCode: true });
public static readonly NodeJS43 = new Runtime('nodejs4.3', RuntimeFamily.NodeJS, { supportsInlineCode: true });
public static readonly NodeJS610 = new Runtime('nodejs6.10', RuntimeFamily.NodeJS, { supportsInlineCode: true });
public static readonly NodeJS810 = new Runtime('nodejs8.10', RuntimeFamily.NodeJS, { supportsInlineCode: true });
public static readonly Python27 = new Runtime('python2.7', RuntimeFamily.Python, { supportsInlineCode: true });
public static readonly Python36 = new Runtime('python3.6', RuntimeFamily.Python, { supportsInlineCode: true });
public static readonly Java8 = new Runtime('java8', RuntimeFamily.Java);
public static readonly DotNetCore1 = new Runtime('dotnetcore1.0', RuntimeFamily.DotNetCore);
public static readonly DotNetCore2 = new Runtime('dotnetcore2.0', RuntimeFamily.DotNetCore);
public static readonly DotNetCore21 = new Runtime('dotnetcore2.1', RuntimeFamily.DotNetCore);
public static readonly Go1x = new Runtime('go1.x', RuntimeFamily.Go);

/** The name of this runtime, as expected by the Lambda resource. */
/**
* The name of this runtime, as expected by the Lambda resource.
*/
public readonly name: string;
/** Whether the ``ZipFile`` (aka inline code) property can be used with this runtime. */

/**
* Whether the ``ZipFile`` (aka inline code) property can be used with this
* runtime.
*/
public readonly supportsInlineCode: boolean;

constructor(name: string, props: LambdaRuntimeProps = {}) {
/**
* The runtime family.
*/
public readonly family?: RuntimeFamily;

constructor(name: string, family?: RuntimeFamily, props: LambdaRuntimeProps = { }) {
this.name = name;
this.supportsInlineCode = !!props.supportsInlineCode;
this.family = family;
}

public toString(): string {
return this.name;
}
}

/**
* A ``LambdaRuntime`` that can be used in conjunction with the ``ZipFile``
* property of the ``AWS::Lambda::Function`` resource.
*/
export interface InlinableRuntime {
readonly name: string;
readonly supportsInlineCode: boolean;
}

/**
* A ``LambdaRuntime`` that can be used for inlining JavaScript.
*/
// tslint:disable-next-line:no-empty-interface this is a marker to allow type-safe declarations
export interface InlinableJavaScriptRuntime extends InlinableRuntime {}
Loading

0 comments on commit 36f29b6

Please sign in to comment.