├── app ├── __init__.py ├── .gitignore └── main.py ├── helpers ├── __init__.py └── utils.py ├── requirements.txt ├── infrastructure ├── app.variables.sample.tf ├── auth.variables.sample.tf ├── main.tf └── lambda │ ├── variables.sample.tf │ └── main.tf ├── .travis.yml ├── tests └── test_dependencies.py ├── makefile ├── LICENSE.md ├── .gitignore └── README.md /app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /helpers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | settings.py 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cov-core 2 | nose2 3 | codecov 4 | 5 | pandas 6 | -------------------------------------------------------------------------------- /app/main.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | 4 | def handler(event, context): 5 | 6 | return ':)' 7 | 8 | -------------------------------------------------------------------------------- /helpers/utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | with open('config.json', 'r') as config: 4 | CONFIG = json.load(config) 5 | 6 | -------------------------------------------------------------------------------- /infrastructure/app.variables.sample.tf: -------------------------------------------------------------------------------- 1 | variable "app_name" { 2 | default = "MyService" 3 | } 4 | 5 | variable "app_region" { 6 | default = "us-west-1" 7 | } 8 | -------------------------------------------------------------------------------- /infrastructure/auth.variables.sample.tf: -------------------------------------------------------------------------------- 1 | variable "auth_credentials_file" { 2 | default = "/home/user/.aws/credentials" 3 | } 4 | 5 | variable "auth_profile" { 6 | default = "profilename" 7 | } 8 | 9 | variable "account_id" { 10 | default = "" 11 | } 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: false 3 | 4 | language: python 5 | python: 6 | - "2.7" 7 | # command to install dependencies 8 | install: 9 | - pip install -r requirements.txt 10 | # command to run tests 11 | script: nose2 --with-coverage 12 | 13 | after_success: 14 | codecov 15 | -------------------------------------------------------------------------------- /infrastructure/main.tf: -------------------------------------------------------------------------------- 1 | module "lambda" { 2 | source = "./lambda" 3 | app_name = "${var.app_name}" 4 | app_region = "${var.app_region}" 5 | auth_profile = "${var.auth_profile}" 6 | auth_credentials_file = "${var.auth_credentials_file}" 7 | } 8 | -------------------------------------------------------------------------------- /infrastructure/lambda/variables.sample.tf: -------------------------------------------------------------------------------- 1 | variable "payload_path" { 2 | default = "lambda/package.zip" 3 | } 4 | 5 | variable "function_name" { 6 | default = "Service Name" 7 | } 8 | 9 | variable "function_description" { 10 | default = "Service description" 11 | } 12 | 13 | variable "function_timeout" { 14 | default = 10 15 | } 16 | 17 | variable "handler" { 18 | default = "app/main.handler" 19 | } 20 | -------------------------------------------------------------------------------- /tests/test_dependencies.py: -------------------------------------------------------------------------------- 1 | """ Tests to ensure required packages are installed and loaded.""" 2 | from nose2.compat import unittest 3 | # from nose2 import discover, util 4 | 5 | class TestRequiredDependencies(unittest.TestCase): 6 | """ Validate if dependencies are properly installed or included 7 | """ 8 | 9 | def setUp(self): 10 | self.test_pandas_isinstalled() 11 | 12 | def tearDown(self): 13 | pass 14 | 15 | def test_pandas_isinstalled(self): 16 | """ 17 | Check Pandas library version 18 | """ 19 | 20 | import pandas as pd 21 | 22 | self.assertGreaterEqual(pd.__version__, '0.19.2') 23 | 24 | 25 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | setup: 2 | rm -rf venv/ 3 | virtualenv venv/ --no-site-packages 4 | venv/bin/pip install -r requirements.txt 5 | run: 6 | . venv/bin/activate; python app/main.py 7 | 8 | houston: 9 | . venv/bin/activate; nose2 -v 10 | 11 | lambda_package: setup 12 | rm -rf package/ && mkdir -p package/ && mkdir -p storage/ 13 | cp -r venv/lib/python2.7/site-packages/* package/ 14 | cp -r app/ package/ 15 | cp -r helpers/ package/ 16 | cd package; zip -r package.zip . -x \*.git\* \*env\* *.zip 17 | mv package/package.zip infrastructure/lambda/ 18 | cd infrastructure/ && terraform get 19 | @echo "Done building AWS Lambda package in infrastructure/lambda/package.zip" 20 | 21 | deploy_test: 22 | cd infrastructure/ && terraform plan 23 | deploy: 24 | cd infrastructure/ && terraform apply 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/setting.py 2 | **/*.zip 3 | data/*.csv 4 | **/*.DS_Store 5 | package/ 6 | 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | env/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *,cover 53 | .hypothesis/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # pyenv 80 | .python-version 81 | 82 | # celery beat schedule file 83 | celerybeat-schedule 84 | 85 | # dotenv 86 | .env 87 | 88 | # virtualenv 89 | .venv/ 90 | venv/ 91 | ENV/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | 96 | # Rope project settings 97 | .ropeproject 98 | storage/*.csv 99 | **/*.tfstate 100 | **/*.backup 101 | **/.terraform/ 102 | **/*.variables.tf 103 | **/*/variables.tf 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/moesy/lambda.service.skeleton.svg?branch=master)](https://travis-ci.org/moesy/lambda.service.skeleton) [![codecov](https://codecov.io/gh/moesy/lambda.service.skeleton/branch/master/graph/badge.svg)](https://codecov.io/gh/moesy/lambda.service.skeleton) 2 | 3 | ## Lambda Service Skeleton 4 | 5 | A skeleton application for deploying microservices on AWS Lambda. 6 | 7 | This template aims to reduce the pain inherent in deploying services to AWS Lambda. 8 | By using a virtual environment locally we are able to isolate package resources from our 9 | global environment and ship them along with our payload to lambda since as of this time a package 10 | manager is not included with the service. 11 | 12 | ===================================== 13 | 14 | - Declare required binaries in requirements.txt 15 | - Build your application in the app/ directory 16 | - edit every file that ends in variables.tf inside of infrastructure/ 17 | - Prepare deploy package 18 | 19 | 20 | Prerequesites 21 | ------------ 22 | - [sudo] pip install virtualenv 23 | - sudo pip install awscli --ignore-installed six 24 | - Install Terraform https://www.terraform.io 25 | 26 | 27 | Installation 28 | ------------ 29 | - clone repo 30 | - edit variable.tf files in infrastructure/ 31 | - begin building your application in app/ 32 | - set your dependencies in requirements.txt 33 | 34 | Commands 35 | ------------ 36 | - make lambda_package: Prepare the Lambda Deployment package infrastructure/lambda/package.zip 37 | - make deploy_test: Preview changes to AWS Infrastructure 38 | - make deploy: deploy service to AWS (must run lambda_package first) 39 | - make run: run your application locally (no need to be in the venv) 40 | - make houston: run nose unit tests 41 | 42 | MANUAL DEPLOY 43 | ------------ 44 | If you do not want to use terraform or prefer the GUI for any other reason simply upload the payload 45 | using the browser and the AWS Console. 46 | -------------------------------------------------------------------------------- /infrastructure/lambda/main.tf: -------------------------------------------------------------------------------- 1 | variable "app_name" {} 2 | variable "app_region" {} 3 | variable "auth_profile" {} 4 | variable "auth_credentials_file" {} 5 | 6 | provider "aws" { 7 | region = "${var.app_region}" 8 | shared_credentials_file = "${var.auth_credentials_file}" 9 | profile = "${var.auth_profile}" 10 | } 11 | 12 | resource "aws_iam_role_policy" "lambda-invoke" { 13 | name = "${var.function_name}-lambda-invoke" 14 | role = "${aws_iam_role.main.id}" 15 | 16 | policy = <