Skip to content

Update .NET blank-csharp example to demonstrate using dotnet lambda CLI for layers #445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 29, 2023
Merged
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
Binary file added .DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions sample-apps/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "automatic",
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable"
}
12 changes: 12 additions & 0 deletions sample-apps/blank-csharp-with-layer/1-create-bucket-and-role.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash
BUCKET_ID=$(dd if=/dev/random bs=8 count=1 2>/dev/null | od -An -tx1 | tr -d ' \t\n')
BUCKET_NAME=lambda-artifacts-$BUCKET_ID
LAYER_BUCKET_NAME=$BUCKET_NAME-dotnet-layer
echo $BUCKET_NAME > bucket-name.txt
aws s3 mb s3://$BUCKET_NAME
aws s3 mb s3://$LAYER_BUCKET_NAME

aws iam create-role --role-name blank-csharp-role --assume-role-policy-document file://assume-policy.json
aws iam attach-role-policy --role-name blank-csharp-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam attach-role-policy --role-name blank-csharp-role --policy-arn arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess
aws iam attach-role-policy --role-name blank-csharp-role --policy-arn arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
6 changes: 6 additions & 0 deletions sample-apps/blank-csharp-with-layer/2-build-layer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
LAYER_BUCKET_NAME=$(cat bucket-name.txt)-dotnet-layer
cd src/blank-csharp
LAYER_ARN=$(dotnet lambda publish-layer blank-csharp-layer --layer-type runtime-package-store --s3-bucket "$LAYER_BUCKET_NAME" | tail -1 | cut -c 23-)
cd ../..
echo $LAYER_ARN > layer-arn.txt
7 changes: 7 additions & 0 deletions sample-apps/blank-csharp-with-layer/3-deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
set -eo pipefail
ARTIFACT_BUCKET=$(cat bucket-name.txt)
LAYER_ARN=$(cat layer-arn.txt)
cd src/blank-csharp
dotnet lambda deploy-function blank-csharp --function-layers $LAYER_ARN
cd ../../
9 changes: 9 additions & 0 deletions sample-apps/blank-csharp-with-layer/4-invoke.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
set -eo pipefail
if [[ $(aws --version) =~ "aws-cli/2." ]]; then PAYLOAD_PROTOCOL="fileb"; else PAYLOAD_PROTOCOL="file"; fi;
while true; do
aws lambda invoke --function-name blank-csharp --payload $PAYLOAD_PROTOCOL://event.json out.json
cat out.json
echo ""
sleep 2
done
50 changes: 50 additions & 0 deletions sample-apps/blank-csharp-with-layer/5-cleanup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/bash
set -eo pipefail
echo "Deleting function blank-csharp"
aws iam detach-role-policy --role-name blank-csharp-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
aws iam detach-role-policy --role-name blank-csharp-role --policy-arn arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess
aws iam detach-role-policy --role-name blank-csharp-role --policy-arn arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess
aws iam delete-role --role-name blank-csharp-role
aws lambda delete-function --function-name blank-csharp

if [ -f bucket-name.txt ]; then
ARTIFACT_BUCKET=$(cat bucket-name.txt)
if [[ ! $ARTIFACT_BUCKET =~ lambda-artifacts-[a-z0-9]{16} ]] ; then
echo "Bucket was not created by this application. Skipping."
else
while true; do
read -p "Delete deployment artifacts and bucket ($ARTIFACT_BUCKET)? (y/n)" response
case $response in
[Yy]* ) aws s3 rb --force s3://$ARTIFACT_BUCKET; break;;
[Nn]* ) break;;
* ) echo "Response must start with y or n.";;
esac
done
fi
LAYER_BUCKET=$(cat bucket-name.txt)-dotnet-layer
if [[ ! $LAYER_BUCKET =~ lambda-artifacts-[a-z0-9]{16}-dotnet-layer ]] ; then
echo "Layer bucket was not created by this application. Skipping."
else
while true; do
read -p "Delete deployment artifacts and bucket ($LAYER_BUCKET)? (y/n)" response
case $response in
[Yy]* ) aws s3 rb --force s3://$LAYER_BUCKET; break;;
[Nn]* ) break;;
* ) echo "Response must start with y or n.";;
esac
done
fi
fi
rm bucket-name.txt

while true; do
read -p "Delete function log group (/aws/lambda/blank-csharp)? (y/n)" response
case $response in
[Yy]* ) aws logs delete-log-group --log-group-name /aws/lambda/blank-csharp; break;;
[Nn]* ) break;;
* ) echo "Response must start with y or n.";;
esac
done

rm -f out.yml out.json layer-arn.txt
rm -rf src/blank-csharp/bin src/blank-csharp/obj
101 changes: 101 additions & 0 deletions sample-apps/blank-csharp-with-layer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Blank function with layer (C#)

![Architecture](/sample-apps/blank-csharp/images/sample-blank-csharp.png)

The project source includes function code and supporting resources:

- `src/blank-csharp` - A C# .NET Core function.
- `1-create-bucket.sh`, `2-deploy.sh`, etc. - Shell scripts that use the AWS CLI to deploy and manage the application.

Use the following instructions to deploy the sample application. For more information on the application's architecture and implementation, see [Managing Spot Instance Requests](https://docs.aws.amazon.com/lambda/latest/dg/services-ec2-tutorial.html) in the developer guide.

# Requirements
- [.NET Core SDK 6.0](https://dotnet.microsoft.com/download/dotnet-core/6.0)
- [AWS extensions for .NET CLI](https://github.com/aws/aws-extensions-for-dotnet-cli). Specifically, ensure that you have [Amazon.Lambda.Tools](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) installed.
- The Bash shell. For Linux and macOS, this is included by default. In Windows 10, you can install the [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) to get a Windows-integrated version of Ubuntu and Bash.
- [The AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) v1.17 or newer.

If you use the AWS CLI v2, add the following to your [configuration file](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) (`~/.aws/config`):

```
cli_binary_format=raw-in-base64-out
```

This setting enables the AWS CLI v2 to load JSON events from a file, matching the v1 behavior.

# Setup
Download or clone this repository.

$ git clone https://github.com/awsdocs/aws-lambda-developer-guide.git
$ cd aws-lambda-developer-guide/sample-apps/blank-csharp

To create a new bucket for deployment artifacts, run `1-create-bucket-and-role.sh`.

blank-csharp$ ./1-create-bucket.sh
make_bucket: lambda-artifacts-d7aec9f2022ef2b4
make_bucket: lambda-artifacts-d7aec9f2022ef2b4-dotnet-layer
{
"Role": {
"Path": "/",
"RoleName": "blank-csharp-role",
"RoleId": "AROA6HOIFXAKKWARP5RSC",
"Arn": "arn:aws:iam::978061735956:role/blank-csharp-role",
"CreateDate": "2023-08-22T18:12:29+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
}
}
]
}
}
}

To build a Lambda layer that contains the function's runtime dependencies, run `2-build-layer.sh`. This also uploads the layer to an S3 bucket created by the first script.

blank-csharp$ ./2-build-layer.sh

# Deploy
To deploy the application, run `3-deploy.sh`.

blank-csharp$ ./3-deploy.sh
Amazon Lambda Tools for .NET Core applications (5.8.0)
...
Created publish archive ...
Creating new Lambda function blank-csharp
New Lambda function created

This script uses the .NET Amazon Lambda Tools to deploy the Lambda function. It uses the default settings from the `src/aws-lambda-tools-defaults.json` file.

To invoke the function, run `4-invoke.sh`.

blank-csharp$ ./4-invoke.sh
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
{"FunctionCount":13,"TotalCodeSize":598094248}

Let the script invoke the function a few times and then press `CRTL+C` to exit.

The application uses AWS X-Ray to trace requests. Open the [X-Ray console](https://console.aws.amazon.com/xray/home#/service-map) to view the service map. The following service map shows the function managing spot instances in Amazon EC2.

![Service Map](/sample-apps/blank-csharp-with-layer/images/blank-csharp-servicemap.png)

Choose a node in the main function graph. Then choose **View traces** to see a list of traces. Choose any trace to view a timeline that breaks down the work done by the function.

![Trace](/sample-apps/blank-csharp-with-layer/images/blank-csharp-trace.png)

# Cleanup
To delete the application, run the cleanup script.

blank-csharp$ ./5-cleanup.sh
16 changes: 16 additions & 0 deletions sample-apps/blank-csharp-with-layer/assume-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sts:AssumeRole"
],
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
}
}
]
}
20 changes: 20 additions & 0 deletions sample-apps/blank-csharp-with-layer/event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"Records": [
{
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
"receiptHandle": "MessageReceiptHandle",
"body": "Hello from SQS!",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1523232000000",
"SenderId": "123456789012",
"ApproximateFirstReceiveTimestamp": "1523232000001"
},
"messageAttributes": {},
"md5OfBody": "7b270e59b47ff90a553787216d55d91d",
"eventSource": "aws:sqs",
"eventSourceARN": "arn:aws:sqs:us-west-2:123456789012:MyQueue",
"awsRegion": "us-west-2"
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 72 additions & 0 deletions sample-apps/blank-csharp-with-layer/src/blank-csharp/Function.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Amazon;
using Amazon.Util;
using Amazon.Lambda;
using Amazon.Lambda.Model;
using Amazon.Lambda.Core;
using Amazon.Lambda.SQSEvents;
using Amazon.XRay.Recorder.Core;
using Amazon.XRay.Recorder.Handlers.AwsSdk;
using System.IO;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace blankCsharp
{
public class Function
{
private AmazonLambdaClient lambdaClient;

public Function()
{
initialize();
}

async void initialize()
{
AWSSDKHandler.RegisterXRayForAllServices();
lambdaClient = new AmazonLambdaClient();
await callLambda();
}

public async Task<AccountUsage> FunctionHandler(SQSEvent invocationEvent, ILambdaContext context)
{
GetAccountSettingsResponse accountSettings;
try
{
accountSettings = await callLambda();
}
catch (AmazonLambdaException ex)
{
throw ex;
}

AccountUsage accountUsage = accountSettings.AccountUsage;
MemoryStream logData = new MemoryStream();
StreamReader logDataReader = new StreamReader(logData);

Amazon.Lambda.Serialization.Json.JsonSerializer serializer = new Amazon.Lambda.Serialization.Json.JsonSerializer();

serializer.Serialize<System.Collections.IDictionary>(System.Environment.GetEnvironmentVariables(), logData);
LambdaLogger.Log("ENVIRONMENT VARIABLES: " + logDataReader.ReadLine());
logData.Position = 0;
serializer.Serialize<ILambdaContext>(context, logData);
LambdaLogger.Log("CONTEXT: " + logDataReader.ReadLine());
logData.Position = 0;
serializer.Serialize<SQSEvent>(invocationEvent, logData);
LambdaLogger.Log("EVENT: " + logDataReader.ReadLine());

return accountUsage;
}

public async Task<GetAccountSettingsResponse> callLambda()
{
var request = new GetAccountSettingsRequest();
var response = await lambdaClient.GetAccountSettingsAsync(request);
return response;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"Information" : [
"This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
"To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",

"dotnet lambda help",

"All the command line options for the Lambda command can be specified in this file."
],

"profile":"default",
"region" : "us-east-1",
"configuration" : "Release",
"framework" : "net6.0",
"function-runtime":"dotnet6",
"function-memory-size" : 512,
"function-timeout" : 30,
"function-handler" : "blank-csharp::blankCsharp.Function::FunctionHandler",
"function-role" : "blank-csharp-role"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<AWSProjectType>Lambda</AWSProjectType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Amazon.Lambda.Core" Version="2.1.0" />
<PackageReference Include="Amazon.Lambda.SQSEvents" Version="2.1.0" />
<PackageReference Include="Amazon.Lambda.Serialization.Json" Version="2.1.0" />
<PackageReference Include="AWSSDK.Core" Version="3.7.103.24" />
<PackageReference Include="AWSSDK.Lambda" Version="3.7.104.3" />
<PackageReference Include="AWSXRayRecorder.Core" Version="2.13.0" />
<PackageReference Include="AWSXRayRecorder.Handlers.AwsSdk" Version="2.11.0" />
</ItemGroup>
</Project>
Loading