Skip to content
This repository was archived by the owner on Jun 8, 2022. It is now read-only.
Closed
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function name unique per region, for example by setting
| attach\_dead\_letter\_config | Set this to true if using the dead_letter_config variable | string | `"false"` | no |
| attach\_policy | Set this to true if using the policy variable | string | `"false"` | no |
| attach\_vpc\_config | Set this to true if using the vpc_config variable | string | `"false"` | no |
| build\_script | The path to a custom build script for creating the Lambda package zip file (defaults to the included build.py) | string | `""` | no |
| dead\_letter\_config | Dead letter configuration for the Lambda function | map | `<map>` | no |
| description | Description of what your Lambda function does | string | `"Managed by Terraform"` | no |
| enable\_cloudwatch\_logs | Set this to false to disable logging your Lambda output to CloudWatch Logs | string | `"true"` | no |
Expand Down
5 changes: 3 additions & 2 deletions archive.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ data "external" "archive" {
program = ["${path.module}/hash.py"]

query = {
runtime = "${var.runtime}"
source_path = "${var.source_path}"
runtime = "${var.runtime}"
source_path = "${var.source_path}"
build_script = "${coalesce(var.build_script, "${path.module}/build.py")}"
}
}

Expand Down
8 changes: 5 additions & 3 deletions hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,24 @@ def update_hash(hash_obj, file_root, file_path):
query = {
'runtime': 'python3.6',
'source_path': os.path.join(current_dir, 'tests', 'python3-pip', 'lambda'),
'build_script': os.path.join(current_dir, 'build.py'),
}
else:
query = json.load(sys.stdin)
runtime = query['runtime']
source_path = query['source_path']
build_script = query['build_script']

# Validate the query.
if not source_path:
abort('source_path must be set.')

# Generate a hash based on file names and content. Also use the
# runtime value and content of build.py because they can have an
# runtime value and content of the build script because they can have an
# effect on the resulting archive.
content_hash = generate_content_hash(source_path)
content_hash.update(runtime.encode())
with open(os.path.join(current_dir, 'build.py'), 'rb') as build_script_file:
with open(build_script, 'rb') as build_script_file:
content_hash.update(build_script_file.read())

# Generate a unique filename based on the hash.
Expand All @@ -146,7 +148,7 @@ def update_hash(hash_obj, file_root, file_path):

# Determine the command to run if Terraform wants to build a new archive.
build_command = "{build_script} {build_data}".format(
build_script=os.path.join(current_dir, 'build.py'),
build_script=build_script,
build_data=bytes.decode(base64.b64encode(str.encode(
json.dumps({
'filename': filename,
Expand Down
42 changes: 42 additions & 0 deletions tests/build-script/lambda/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash
#
# Compiles a Python package into a zip deployable on AWS Lambda.
#
# - Builds Python dependencies into the package, using a Docker image to
# correctly build native extensions
# - Able to be used with the terraform-aws-lambda module
#
# Dependencies:
#
# - Docker
# - base64
# - jq
#
# Usage:
#
# $ ./build.sh "$(echo { \"filename\": \"out.zip\", \"runtime\": \"python3.7\", \"source_path\": \".\" \} | jq . | base64)"
#
# - Arguments to be provided as JSON, then Base64 encoded

set -euo pipefail

# Extract variables from the JSON-formatted, Base64 encoded input argument.
# This is to conform to arguments as passed in by hash.py
eval "$(echo $1 | base64 --decode | jq -r '@sh "FILENAME=\(.filename) RUNTIME=\(.runtime) SOURCE_PATH=\(.source_path)"')"

# Convert to absolute paths
SOURCE_DIR=$(cd "$SOURCE_PATH" && pwd)
ZIP_DIR=$(cd "$(dirname "$FILENAME")" && pwd)
ZIP_NAME=$(basename "$FILENAME")

# Install dependencies, using a Docker image to correctly build native extensions
docker run --rm -t -v "$SOURCE_DIR:/src" -v "$ZIP_DIR:/out" lambci/lambda:build-$RUNTIME sh -c "
cp -r /src /build &&
cd /build &&
pip install -r requirements.txt -t . &&
chmod -R 755 . &&
zip -r /out/$ZIP_NAME * &&
chown \$(stat -c '%u:%g' /out) /out/$ZIP_NAME
"

echo "Created $FILENAME from $SOURCE_PATH"
6 changes: 6 additions & 0 deletions tests/build-script/lambda/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def lambda_handler(event, context):
print('importing numpy package')
import numpy as np
print('checking numpy works correctly')
assert np.array_equal(np.array([1, 2]) + 3, np.array([4, 5]))
return 'test passed'
3 changes: 3 additions & 0 deletions tests/build-script/lambda/src/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# numpy has native extensions, needs a custom build script to
# install correctly if your host OS differs to Lambda OS
numpy
21 changes: 21 additions & 0 deletions tests/build-script/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
terraform {
backend "local" {
path = "terraform.tfstate"
}
}

provider "aws" {
region = "eu-west-1"
}

module "lambda" {
source = "../../"

function_name = "terraform-aws-lambda-test-build-script"
description = "Test custom build script functionality in terraform-aws-lambda"
handler = "main.lambda_handler"
runtime = "python3.7"

source_path = "${path.module}/lambda/src"
build_script = "${path.module}/lambda/build.sh"
}
6 changes: 6 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ variable "source_path" {
type = "string"
}

variable "build_script" {
description = "The path to a custom build script for creating the Lambda package zip file (defaults to the included build.py)"
type = "string"
default = ""
}

variable "description" {
description = "Description of what your Lambda function does"
type = "string"
Expand Down