From bfa8b4552c754a5b1e476d197700c3c189307c5a Mon Sep 17 00:00:00 2001 From: Hugo Lopes Tavares Date: Wed, 17 May 2017 18:16:40 -0400 Subject: [PATCH] Fix CloudFormation Lambda ZipFile implementation to be plain text The AWS CloudFormation documentation[1] states the following about the ZipFile property: > For nodejs4.3, nodejs6.10, python2.7, and python3.6 runtime environments, the source code of your Lambda function. > You can't use this property with other runtime environments. [1]: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#cfn-lambda-function-code-zipfile --- moto/awslambda/models.py | 16 ++++++++++++ .../test_cloudformation_stack_integration.py | 26 +++++-------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index a3b1f715f..1e651cb04 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -198,10 +198,26 @@ class LambdaFunction(BaseModel): if prop in properties: spec[prop] = properties[prop] + # when ZipFile is present in CloudFormation, per the official docs, + # the code it's a plaintext code snippet up to 4096 bytes. + # this snippet converts this plaintext code to a proper base64-encoded ZIP file. + if 'ZipFile' in properties['Code']: + spec['Code']['ZipFile'] = base64.b64encode( + cls._create_zipfile_from_plaintext_code(spec['Code']['ZipFile'])) + backend = lambda_backends[region_name] fn = backend.create_function(spec) return fn + @staticmethod + def _create_zipfile_from_plaintext_code(code): + zip_output = io.BytesIO() + zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED) + zip_file.writestr('lambda_function.zip', code) + zip_file.close() + zip_output.seek(0) + return zip_output.read() + class LambdaBackend(BaseBackend): diff --git a/tests/test_cloudformation/test_cloudformation_stack_integration.py b/tests/test_cloudformation/test_cloudformation_stack_integration.py index 2480ee051..87dcfd950 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_integration.py +++ b/tests/test_cloudformation/test_cloudformation_stack_integration.py @@ -1846,29 +1846,14 @@ def test_datapipeline(): data_pipelines['pipelineIdList'][0]['id']) -def _process_lamda(pfunc): - import io - import zipfile - zip_output = io.BytesIO() - zip_file = zipfile.ZipFile(zip_output, 'w', zipfile.ZIP_DEFLATED) - zip_file.writestr('lambda_function.zip', pfunc) - zip_file.close() - zip_output.seek(0) - return zip_output.read() - - -def get_test_zip_file1(): - pfunc = """ -def lambda_handler(event, context): - return (event, context) -""" - return _process_lamda(pfunc) - - @mock_cloudformation @mock_lambda def test_lambda_function(): # switch this to python as backend lambda only supports python execution. + lambda_code = """ +def lambda_handler(event, context): + return (event, context) +""" template = { "AWSTemplateFormatVersion": "2010-09-09", "Resources": { @@ -1876,7 +1861,8 @@ def test_lambda_function(): "Type": "AWS::Lambda::Function", "Properties": { "Code": { - "ZipFile": base64.b64encode(get_test_zip_file1()).decode('utf-8') + # CloudFormation expects a string as ZipFile, not a ZIP file base64-encoded + "ZipFile": {"Fn::Join": ["\n", lambda_code.splitlines()]} }, "Handler": "lambda_function.handler", "Description": "Test function",