Skip to content

Commit

Permalink
feat(sdk): aws lambda layers (#6790)
Browse files Browse the repository at this point in the history
Closes #6761 

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [x] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
Chriscbr committed Jun 26, 2024
1 parent 95857b5 commit 734a760
Show file tree
Hide file tree
Showing 13 changed files with 255 additions and 7 deletions.
21 changes: 21 additions & 0 deletions docs/docs/04-standard-library/aws/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -1727,6 +1727,27 @@ AWS Dynamodb name.

A shared interface for AWS functions.

#### Methods <a name="Methods" id="Methods"></a>

| **Name** | **Description** |
| --- | --- |
| <code><a href="#@winglang/sdk.aws.IAwsFunction.addLambdaLayer">addLambdaLayer</a></code> | Add a Lambda layer to the function. |

---

##### `addLambdaLayer` <a name="addLambdaLayer" id="@winglang/sdk.aws.IAwsFunction.addLambdaLayer"></a>

```wing
addLambdaLayer(layerArn: str): void
```

Add a Lambda layer to the function.

###### `layerArn`<sup>Required</sup> <a name="layerArn" id="@winglang/sdk.aws.IAwsFunction.addLambdaLayer.parameter.layerArn"></a>

- *Type:* str

---

#### Properties <a name="Properties" id="Properties"></a>

Expand Down
11 changes: 11 additions & 0 deletions examples/tests/doc_examples/valid/function.md_example_5/main.w

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

24 changes: 24 additions & 0 deletions examples/tests/doc_examples/valid/function.md_example_6/main.w

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

20 changes: 20 additions & 0 deletions examples/tests/sdk_tests/function/aws-layer.test.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
bring aws;
bring cloud;
bring expect;
bring util;

if util.env("WING_TARGET") == "tf-aws" {
let fn = new cloud.Function(inflight () => {
return "Hello world!";
});

if let lambda = aws.Function.from(fn) {
// Using a public layer from https://docs.powertools.aws.dev/lambda/typescript/latest/
lambda.addLambdaLayer("arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:7");
}

test "the function runs" {
let result = fn.invoke();
expect.equal(result, "Hello world!");
}
}
10 changes: 10 additions & 0 deletions libs/awscdk/src/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Function as CdkFunction,
Code,
Runtime,
LayerVersion,
} from "aws-cdk-lib/aws-lambda";
import { LogGroup, RetentionDays } from "aws-cdk-lib/aws-logs";
import { Asset } from "aws-cdk-lib/aws-s3-assets";
Expand Down Expand Up @@ -96,6 +97,15 @@ export class Function
this.assetPath = asset.assetPath;
}

public addLambdaLayer(layerArn: string): void {
const layer = LayerVersion.fromLayerVersionArn(
this,
`Layer${layerArn}`,
layerArn
);
this.function.addLayers(layer);
}

/** @internal */
public _preSynthesize(): void {
super._preSynthesize();
Expand Down
6 changes: 6 additions & 0 deletions libs/wingsdk/src/shared-aws/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export interface IAwsFunction extends IAwsInflightHost {
* AWS Function name
*/
readonly functionName: string;

/**
* Add a Lambda layer to the function.
* @param layer The ARN of the layer.
*/
addLambdaLayer(layerArn: string): void;
}

/**
Expand Down
15 changes: 15 additions & 0 deletions libs/wingsdk/src/target-tf-aws/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class Function extends cloud.Function implements IAwsFunction {
private subnets?: Set<string>;
private vpcPermissionsAdded = false;
private securityGroups?: Set<string>;
private layers?: Set<string>;

/**
* Qualified Function ARN
Expand Down Expand Up @@ -201,6 +202,10 @@ export class Function extends cloud.Function implements IAwsFunction {
runtime: "nodejs20.x",
role: this.role.arn,
publish: true,
layers: Lazy.listValue({
produce: () =>
this.layers ? Array.from(this.layers.values()) : undefined,
}),
vpcConfig: {
subnetIds: Lazy.listValue({
produce: () =>
Expand Down Expand Up @@ -319,6 +324,16 @@ export class Function extends cloud.Function implements IAwsFunction {
);
}

/**
* Add a Lambda Layer to the function
*/
public addLambdaLayer(layerArn: string): void {
if (!this.layers) {
this.layers = new Set();
}
this.layers.add(layerArn);
}

/**
* Add VPC configurations to lambda function
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ exports[`captures tokens inside plain objects 1`] = `
console.log(ctx.foo.str, ctx.foo.num);
}
const $ctx = {
foo: {"str": JSON.parse(process.env["WING_TOKEN_HTTPS_TFTOKEN_TOKEN_38_EXECUTE_API_TFTOKEN_TOKEN_30_AMAZONAWS_COM_TFTOKEN_TOKEN_39"]),"num": JSON.parse(process.env["WING_TOKEN_8_109562212591416E_298"]),}
foo: {"str": JSON.parse(process.env["WING_TOKEN_HTTPS_TFTOKEN_TOKEN_39_EXECUTE_API_TFTOKEN_TOKEN_31_AMAZONAWS_COM_TFTOKEN_TOKEN_40"]),"num": JSON.parse(process.env["WING_TOKEN_8_109562212591417E_298"]),}
};
let newFunction = async (...args) => {
return $func($ctx, ...args);
Expand Down Expand Up @@ -246,8 +246,8 @@ exports[`captures tokens inside plain objects 2`] = `
"variables": {
"NODE_OPTIONS": "--enable-source-maps",
"WING_FUNCTION_NAME": "get_0-c86d29bb",
"WING_TOKEN_8_109562212591416E_298": "\${jsonencode(var.Number)}",
"WING_TOKEN_HTTPS_TFTOKEN_TOKEN_38_EXECUTE_API_TFTOKEN_TOKEN_30_AMAZONAWS_COM_TFTOKEN_TOKEN_39": "\${jsonencode("https://\${aws_api_gateway_rest_api.Api_api_91C07D84.id}.execute-api.\${data.aws_region.Region.name}.amazonaws.com/\${aws_api_gateway_stage.Api_api_stage_E0FA39D6.stage_name}")}",
"WING_TOKEN_8_109562212591417E_298": "\${jsonencode(var.Number)}",
"WING_TOKEN_HTTPS_TFTOKEN_TOKEN_39_EXECUTE_API_TFTOKEN_TOKEN_31_AMAZONAWS_COM_TFTOKEN_TOKEN_40": "\${jsonencode("https://\${aws_api_gateway_rest_api.Api_api_91C07D84.id}.execute-api.\${data.aws_region.Region.name}.amazonaws.com/\${aws_api_gateway_stage.Api_api_stage_E0FA39D6.stage_name}")}",
},
},
"function_name": "get_0-c86d29bb",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# [aws-layer.test.w](../../../../../../examples/tests/sdk_tests/function/aws-layer.test.w) | compile | tf-aws

## main.tf.json
```json
{
"//": {
"metadata": {
"backend": "local",
"stackName": "root"
},
"outputs": {}
},
"provider": {
"aws": [
{}
]
},
"resource": {
"aws_cloudwatch_log_group": {
"Function_CloudwatchLogGroup_ABDCF4C4": {
"//": {
"metadata": {
"path": "root/Default/Default/Function/CloudwatchLogGroup",
"uniqueId": "Function_CloudwatchLogGroup_ABDCF4C4"
}
},
"name": "/aws/lambda/Function-c852aba6",
"retention_in_days": 30
}
},
"aws_iam_role": {
"Function_IamRole_678BE84C": {
"//": {
"metadata": {
"path": "root/Default/Default/Function/IamRole",
"uniqueId": "Function_IamRole_678BE84C"
}
},
"assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Effect\":\"Allow\"}]}"
}
},
"aws_iam_role_policy": {
"Function_IamRolePolicy_E3B26607": {
"//": {
"metadata": {
"path": "root/Default/Default/Function/IamRolePolicy",
"uniqueId": "Function_IamRolePolicy_E3B26607"
}
},
"policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":\"none:null\",\"Resource\":\"*\"}]}",
"role": "${aws_iam_role.Function_IamRole_678BE84C.name}"
}
},
"aws_iam_role_policy_attachment": {
"Function_IamRolePolicyAttachment_CACE1358": {
"//": {
"metadata": {
"path": "root/Default/Default/Function/IamRolePolicyAttachment",
"uniqueId": "Function_IamRolePolicyAttachment_CACE1358"
}
},
"policy_arn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
"role": "${aws_iam_role.Function_IamRole_678BE84C.name}"
}
},
"aws_lambda_function": {
"Function": {
"//": {
"metadata": {
"path": "root/Default/Default/Function/Default",
"uniqueId": "Function"
}
},
"architectures": [
"arm64"
],
"environment": {
"variables": {
"NODE_OPTIONS": "--enable-source-maps",
"WING_FUNCTION_NAME": "Function-c852aba6",
"WING_TARGET": "tf-aws"
}
},
"function_name": "Function-c852aba6",
"handler": "index.handler",
"layers": [
"arn:aws:lambda:us-east-1:094274105915:layer:AWSLambdaPowertoolsTypeScriptV2:7"
],
"memory_size": 1024,
"publish": true,
"role": "${aws_iam_role.Function_IamRole_678BE84C.arn}",
"runtime": "nodejs20.x",
"s3_bucket": "${aws_s3_bucket.Code.bucket}",
"s3_key": "${aws_s3_object.Function_S3Object_C62A0C2D.key}",
"timeout": 60,
"vpc_config": {
"security_group_ids": [],
"subnet_ids": []
}
}
},
"aws_s3_bucket": {
"Code": {
"//": {
"metadata": {
"path": "root/Default/Code",
"uniqueId": "Code"
}
},
"bucket_prefix": "code-c84a50b1-"
}
},
"aws_s3_object": {
"Function_S3Object_C62A0C2D": {
"//": {
"metadata": {
"path": "root/Default/Default/Function/S3Object",
"uniqueId": "Function_S3Object_C62A0C2D"
}
},
"bucket": "${aws_s3_bucket.Code.bucket}",
"key": "<ASSET_KEY>",
"source": "<ASSET_SOURCE>"
}
}
}
}
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# [aws-layer.test.w](../../../../../../examples/tests/sdk_tests/function/aws-layer.test.w) | test | sim

## stdout.log
```log
pass ─ aws-layer.test.wsim (no tests)
Tests 1 passed (1)
Snapshots 1 skipped
Test Files 1 passed (1)
Duration <DURATION>
```

Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
"NODE_OPTIONS": "--enable-source-maps",
"WING_FUNCTION_NAME": "Handler-c89bc30b",
"WING_TARGET": "tf-aws",
"WING_TOKEN_TFTOKEN_TOKEN_15": "${jsonencode(aws_lambda_function.Function.arn)}"
"WING_TOKEN_TFTOKEN_TOKEN_16": "${jsonencode(aws_lambda_function.Function.arn)}"
}
},
"function_name": "Handler-c89bc30b",
Expand Down Expand Up @@ -240,7 +240,7 @@
"NODE_OPTIONS": "--enable-source-maps",
"WING_FUNCTION_NAME": "Handler-c8f37d21",
"WING_TARGET": "tf-aws",
"WING_TOKEN_TFTOKEN_TOKEN_15": "${jsonencode(aws_lambda_function.Function.arn)}"
"WING_TOKEN_TFTOKEN_TOKEN_16": "${jsonencode(aws_lambda_function.Function.arn)}"
}
},
"function_name": "Handler-c8f37d21",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@
"NODE_OPTIONS": "--enable-source-maps",
"WING_FUNCTION_NAME": "Handler-c8c3c90a",
"WING_TARGET": "tf-aws",
"WING_TOKEN_TFTOKEN_TOKEN_20": "${jsonencode(aws_sqs_queue.Queue.arn)}"
"WING_TOKEN_TFTOKEN_TOKEN_21": "${jsonencode(aws_sqs_queue.Queue.arn)}"
}
},
"function_name": "Handler-c8c3c90a",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ module.exports = function({ }) {
"NODE_OPTIONS": "--enable-source-maps",
"WING_FUNCTION_NAME": "get_endpoint10-c8e91512",
"WING_TARGET": "tf-aws",
"WING_TOKEN_HTTPS_TFTOKEN_TOKEN_33_EXECUTE_API_TFTOKEN_TOKEN_25_AMAZONAWS_COM_TFTOKEN_TOKEN_34": "${jsonencode(\"https://${aws_api_gateway_rest_api.A_Api_api_06466CBC.id}.execute-api.${data.aws_region.Region.name}.amazonaws.com/${aws_api_gateway_stage.A_Api_api_stage_75CEFF9A.stage_name}\")}"
"WING_TOKEN_HTTPS_TFTOKEN_TOKEN_34_EXECUTE_API_TFTOKEN_TOKEN_26_AMAZONAWS_COM_TFTOKEN_TOKEN_35": "${jsonencode(\"https://${aws_api_gateway_rest_api.A_Api_api_06466CBC.id}.execute-api.${data.aws_region.Region.name}.amazonaws.com/${aws_api_gateway_stage.A_Api_api_stage_75CEFF9A.stage_name}\")}"
}
},
"function_name": "get_endpoint10-c8e91512",
Expand Down

0 comments on commit 734a760

Please sign in to comment.