Skip to content

Commit

Permalink
Adding support for .NET Core 2.0 Lambda's (#693)
Browse files Browse the repository at this point in the history
  • Loading branch information
hartmannr76 authored and whummer committed Apr 16, 2018
1 parent 3e1107c commit 1bc2d02
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ localstack/infra/
~*
*~
/.idea
**/obj/**
**/bin/**
18 changes: 13 additions & 5 deletions localstack/services/awslambda/lambda_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
LAMBDA_RUNTIME_NODEJS,
LAMBDA_RUNTIME_NODEJS610,
LAMBDA_RUNTIME_JAVA8,
LAMBDA_RUNTIME_DOTNETCORE2,
LAMBDA_RUNTIME_GOLANG)
from localstack.utils.common import (to_str, load_file, save_file, TMP_FILES, ensure_readable,
mkdir, unzip, is_zip_file, run, short_uid, is_jar_archive, timestamp, TIMESTAMP_FORMAT_MILLIS)
Expand All @@ -39,7 +40,7 @@
LAMBDA_SCRIPT_PATTERN = '%s/lambda_script_*.py' % config.TMP_FOLDER

# List of Lambda runtime names. Keep them in this list, mainly to silence the linter
LAMBDA_RUNTIMES = [LAMBDA_RUNTIME_PYTHON27, LAMBDA_RUNTIME_PYTHON36,
LAMBDA_RUNTIMES = [LAMBDA_RUNTIME_PYTHON27, LAMBDA_RUNTIME_PYTHON36, LAMBDA_RUNTIME_DOTNETCORE2,
LAMBDA_RUNTIME_NODEJS, LAMBDA_RUNTIME_NODEJS610, LAMBDA_RUNTIME_JAVA8]

LAMBDA_DEFAULT_HANDLER = 'handler.handler'
Expand Down Expand Up @@ -219,7 +220,7 @@ def publish_new_function_version(arn):
else:
last_version = max([int(key) for key in versions.keys() if key != '$LATEST'])
versions[str(last_version + 1)] = {'CodeSize': versions.get('$LATEST').get('CodeSize'),
'Function': versions.get('$LATEST').get('Function')}
'Function': versions.get('$LATEST').get('Function')}
return get_function_version(arn, str(last_version + 1))


Expand Down Expand Up @@ -298,18 +299,25 @@ def exec_lambda_code(script, handler_function='handler', lambda_cwd=None, lambda

def get_handler_file_from_name(handler_name, runtime=LAMBDA_DEFAULT_RUNTIME):
# TODO: support Java Lambdas in the future
delimiter = '.'
if runtime.startswith(LAMBDA_RUNTIME_NODEJS):
file_ext = '.js'
elif runtime.startswith(LAMBDA_RUNTIME_GOLANG):
file_ext = ''
elif runtime.startswith(LAMBDA_RUNTIME_DOTNETCORE2):
file_ext = '.dll'
delimiter = ':'
else:
file_ext = '.py'
return '%s%s' % (handler_name.split('.')[0], file_ext)
return '%s%s' % (handler_name.split(delimiter)[0], file_ext)


def get_handler_function_from_name(handler_name, runtime=LAMBDA_DEFAULT_RUNTIME):
# TODO: support Java Lambdas in the future
return handler_name.split('.')[-1]
if runtime.startswith(LAMBDA_RUNTIME_DOTNETCORE2):
return handler_name.split(':')[-1]
else:
return handler_name.split('.')[-1]


def error_response(msg, code=500, error_type='InternalFailure'):
Expand All @@ -321,7 +329,7 @@ def set_function_code(code, lambda_name):

def generic_handler(event, context):
raise Exception(('Unable to find executor for Lambda function "%s". ' +
'Note that Node.js Lambdas currently require LAMBDA_EXECUTOR=docker') % lambda_name)
'Note that Node.js and .NET Core Lambdas currently require LAMBDA_EXECUTOR=docker') % lambda_name)

lambda_handler = generic_handler
lambda_cwd = None
Expand Down
1 change: 1 addition & 0 deletions localstack/services/awslambda/lambda_executors.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
LAMBDA_RUNTIME_NODEJS = 'nodejs'
LAMBDA_RUNTIME_NODEJS610 = 'nodejs6.10'
LAMBDA_RUNTIME_JAVA8 = 'java8'
LAMBDA_RUNTIME_DOTNETCORE2 = 'dotnetcore2.0'
LAMBDA_RUNTIME_GOLANG = 'go1.x'

LAMBDA_EVENT_FILE = 'event_file.json'
Expand Down
17 changes: 17 additions & 0 deletions tests/integration/lambdas/dotnetcore2/DotNetCore2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.IO;
using Amazon.Lambda.Core;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace DotNetCore2.Lambda
{
public class Function
{
public object SimpleFunctionHandler(Stream input, ILambdaContext context)
{
context.Logger.Log("Running .NET Core 2.0 Lambda");
return new { };
}
}
}
17 changes: 17 additions & 0 deletions tests/integration/lambdas/dotnetcore2/DotNetCore2.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
<PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
</ItemGroup>

<ItemGroup>
<DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="2.1.1" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Information": [
"This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
"All the command line options for the Lambda command can be specified in this file."
],
"profile": "default",
"region": "us-east-1",
"configuration": "Release",
"framework": "netcoreapp2.0",
"function-runtime": "dotnetcore2.0",
"function-memory-size": 256,
"function-timeout": 30,
"function-handler": "DotNetCore2::DotNetCore2.Lambda.Function::SimpleFunctionHandler"
}
Binary file not shown.
17 changes: 16 additions & 1 deletion tests/integration/test_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,21 @@
from localstack.utils.aws import aws_stack
from localstack.utils.common import short_uid, load_file, to_str, mkdir, download
from localstack.services.awslambda import lambda_api, lambda_executors
from localstack.services.awslambda.lambda_api import (LAMBDA_RUNTIME_NODEJS,
from localstack.services.awslambda.lambda_api import (LAMBDA_RUNTIME_NODEJS, LAMBDA_RUNTIME_DOTNETCORE2,
LAMBDA_RUNTIME_PYTHON27, LAMBDA_RUNTIME_PYTHON36, LAMBDA_RUNTIME_JAVA8, use_docker)

THIS_FOLDER = os.path.dirname(os.path.realpath(__file__))
TEST_LAMBDA_PYTHON = os.path.join(THIS_FOLDER, 'lambdas', 'lambda_integration.py')
TEST_LAMBDA_PYTHON3 = os.path.join(THIS_FOLDER, 'lambdas', 'lambda_python3.py')
TEST_LAMBDA_NODEJS = os.path.join(THIS_FOLDER, 'lambdas', 'lambda_integration.js')
TEST_LAMBDA_DOTNETCORE2 = os.path.join(THIS_FOLDER, 'lambdas', 'dotnetcore2', 'dotnetcore2.zip')
TEST_LAMBDA_JAVA = os.path.join(LOCALSTACK_ROOT_FOLDER, 'localstack', 'infra', 'localstack-utils-tests.jar')
TEST_LAMBDA_ENV = os.path.join(THIS_FOLDER, 'lambdas', 'lambda_environment.py')

TEST_LAMBDA_NAME_PY = 'test_lambda_py'
TEST_LAMBDA_NAME_PY3 = 'test_lambda_py3'
TEST_LAMBDA_NAME_JS = 'test_lambda_js'
TEST_LAMBDA_NAME_DOTNETCORE2 = 'test_lambda_dotnetcore2'
TEST_LAMBDA_NAME_JAVA = 'test_lambda_java'
TEST_LAMBDA_NAME_JAVA_STREAM = 'test_lambda_java_stream'
TEST_LAMBDA_NAME_JAVA_SERIALIZABLE = 'test_lambda_java_serializable'
Expand Down Expand Up @@ -148,6 +150,19 @@ def test_lambda_runtimes():
result_data = result['Payload'].read()
assert to_str(result_data).strip() == '{}'

# deploy and invoke - .NET Core 2.0. Its already a zip
zip_file = TEST_LAMBDA_DOTNETCORE2
zip_file_content = None
with open(zip_file, 'rb') as file_obj:
zip_file_content = file_obj.read()
testutil.create_lambda_function(func_name=TEST_LAMBDA_NAME_DOTNETCORE2, zip_file=zip_file_content,
handler='DotNetCore2::DotNetCore2.Lambda.Function::SimpleFunctionHandler',
runtime=LAMBDA_RUNTIME_DOTNETCORE2)
result = lambda_client.invoke(FunctionName=TEST_LAMBDA_NAME_DOTNETCORE2, Payload=b'{}')
assert result['StatusCode'] == 200
result_data = result['Payload'].read()
assert to_str(result_data).strip() == '{}'


def test_lambda_environment():

Expand Down

0 comments on commit 1bc2d02

Please sign in to comment.