Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
.DS_Store
terraform.tfstate
terraform.tfstate.backup
.terraform
File renamed without changes.
50 changes: 50 additions & 0 deletions terraform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# howto
Deploy application with terraform

### Table of Contents
**[Pre-deployment](#pre-deployment)**<br>
**[Deployment](#deployment)**<br>
**[Tests](#tests)**<br>


Pre-deployment
---

Zip your python code:

`zip python.zip lambda.py`

Create a aws s3 bucket with location constraint:

`aws s3api create-bucket --bucket=terraform-serverless-python --create-bucket-configuration LocationConstraint=eu-central-1`

Upload your build artifact into newly created bucket:

`aws s3 cp python.zip s3://terraform-serverless-python/v1.0.0/python.zip`


Deployment
---

Deploy your application with your artifact already available in the s3 bucket

`terraform plan -var="app_version=1.0.0"`

`terraform apply -var="app_version=1.0.0"`

Use `terraform output` to get an output of your API Gateway **base_url**:

```python
terraform output
base_url = https://95q1xx0fol.execute-api.eu-central-1.amazonaws.com/v1
```

Tests
---
Test your lambda function via API Gateway with **curl**:

```python
curl -H "Content-Type: application/json" -X POST -d '{"answer":"def sum(x,y):\n return x-y"}' $(terraform output base_url)/pyexecute
```

Update your `assets/main.js` file with new **base_url**.
83 changes: 83 additions & 0 deletions terraform/api_gateway.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
## API Gateway config
resource "aws_api_gateway_rest_api" "PyAPI" {
name = "TfServerlessPythonAPI"
description = "API for Serverless Python Application Example"
}

resource "aws_api_gateway_resource" "ExecutePyResource" {
rest_api_id = "${aws_api_gateway_rest_api.PyAPI.id}"
parent_id = "${aws_api_gateway_rest_api.PyAPI.root_resource_id}"
path_part = "pyexecute"
}

resource "aws_api_gateway_method" "ExecutePyMethod" {
rest_api_id = "${aws_api_gateway_rest_api.PyAPI.id}"
resource_id = "${aws_api_gateway_resource.ExecutePyResource.id}"
http_method = "POST"
authorization = "NONE"
}

## Lambda Integration
resource "aws_api_gateway_integration" "LambdaIntegration" {
rest_api_id = "${aws_api_gateway_rest_api.PyAPI.id}"
resource_id = "${aws_api_gateway_resource.ExecutePyResource.id}"
http_method = "${aws_api_gateway_method.ExecutePyMethod.http_method}"

integration_http_method = "POST"
type = "AWS"
uri = "${aws_lambda_function.PyLambdaFunction.invoke_arn}"
}

## Response mapping
resource "aws_api_gateway_method_response" "200" {
rest_api_id = "${aws_api_gateway_rest_api.PyAPI.id}"
resource_id = "${aws_api_gateway_resource.ExecutePyResource.id}"
http_method = "${aws_api_gateway_method.ExecutePyMethod.http_method}"
status_code = "200"
}

resource "aws_api_gateway_integration_response" "LambdaIntegrationResponse" {
rest_api_id = "${aws_api_gateway_rest_api.PyAPI.id}"
resource_id = "${aws_api_gateway_resource.ExecutePyResource.id}"
http_method = "${aws_api_gateway_method.ExecutePyMethod.http_method}"
status_code = "${aws_api_gateway_method_response.200.status_code}"
depends_on = ["aws_api_gateway_integration.LambdaIntegration"]
}

## API DEPLOYMENT
resource "aws_api_gateway_deployment" "PyAPIDeployment" {
depends_on = [
"aws_api_gateway_integration.LambdaIntegration"
]

rest_api_id = "${aws_api_gateway_rest_api.PyAPI.id}"
stage_name = "v1"
}

## Permission for API Gateway DEPLOYMENT to access Lambda
resource "aws_lambda_permission" "apigw" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.PyLambdaFunction.arn}"
principal = "apigateway.amazonaws.com"

# The /*/* portion grants access from any method on any resource
# within the API Gateway "REST API".
source_arn = "${aws_api_gateway_deployment.PyAPIDeployment.execution_arn}/*/*"
}

## Permission for API Gateway REST API to access Lambda
resource "aws_lambda_permission" "lambda_permission" {
statement_id = "AllowTfServerlessPythonAPIInvoke"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.PyLambdaFunction.arn}"
principal = "apigateway.amazonaws.com"

# The /*/*/* part allows invocation from any stage, method and resource path
# within API Gateway REST API.
source_arn = "${aws_api_gateway_rest_api.PyAPI.execution_arn}/*/*/*"
}

output "base_url" {
value = "${aws_api_gateway_deployment.PyAPIDeployment.invoke_url}"
}
51 changes: 51 additions & 0 deletions terraform/lambda.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
##
## based on an excellent terrform for lambda example:
## https://www.terraform.io/docs/providers/aws/guides/serverless-with-aws-lambda-and-api-gateway.html
##


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

variable "app_version" {
}

resource "aws_lambda_function" "PyLambdaFunction" {
function_name = "PythonEvalLambda"

# The bucket name as created earlier with "aws s3api create-bucket"
s3_bucket = "terraform-serverless-python"
s3_key = "v${var.app_version}/python.zip"

# "main" is the filename within the zip file (main.py) and "handler"
# is the name of the property under which the handler function was
# exported in that file.
handler = "lambda.lambda_handler"
runtime = "python3.6"

role = "${aws_iam_role.lambda_exec.arn}"
}


# IAM role which dictates what other AWS services the Lambda function
# may access.
resource "aws_iam_role" "lambda_exec" {
name = "serverless_lambda_python"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}