diff --git a/modules/lambda-layer-deps/.gitignore b/modules/lambda-layer-deps/.gitignore new file mode 100644 index 0000000..61f0b08 --- /dev/null +++ b/modules/lambda-layer-deps/.gitignore @@ -0,0 +1,2 @@ +builds/ +package.log \ No newline at end of file diff --git a/modules/lambda-layer-deps/examples/basic-nodejs-npm/main.tf b/modules/lambda-layer-deps/examples/basic-nodejs-npm/main.tf index 7c4c600..088593c 100644 --- a/modules/lambda-layer-deps/examples/basic-nodejs-npm/main.tf +++ b/modules/lambda-layer-deps/examples/basic-nodejs-npm/main.tf @@ -1,5 +1,4 @@ provider "aws" { - profile = "zamboni-development" region = "us-west-1" } diff --git a/modules/lambda-layer-deps/examples/basic-python-poetry/main.tf b/modules/lambda-layer-deps/examples/basic-python-poetry/main.tf index ee460b4..030e2ef 100644 --- a/modules/lambda-layer-deps/examples/basic-python-poetry/main.tf +++ b/modules/lambda-layer-deps/examples/basic-python-poetry/main.tf @@ -1,5 +1,4 @@ provider "aws" { - profile = "zamboni-development" region = "us-west-1" } diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/poetry.lock b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/poetry.lock new file mode 100644 index 0000000..78b5aa4 --- /dev/null +++ b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/poetry.lock @@ -0,0 +1,165 @@ +[[package]] +name = "attrs" +version = "22.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +cov = ["attrs", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs"] +docs = ["furo", "sphinx", "myst-parser", "zope.interface", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["attrs", "zope.interface"] +tests-no-zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] +tests_no_zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] + +[[package]] +name = "certifi" +version = "2022.12.7" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "charset-normalizer" +version = "3.0.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" + +[[package]] +name = "exceptiongroup" +version = "1.1.0" +description = "Backport of PEP 654 (exception groups)" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "packaging" +version = "23.0" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pytest" +version = "7.2.1" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "requests" +version = "2.28.2" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.14" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.extras] +brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "urllib3-secure-extra", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.8" +content-hash = "7a89c5ee8e7cfb71910f1f145a30c5c0f41db9f67c70fd0727232188f54e45f4" + +[metadata.files] +attrs = [] +certifi = [] +charset-normalizer = [] +colorama = [] +exceptiongroup = [] +idna = [] +iniconfig = [] +packaging = [] +pluggy = [] +pytest = [] +requests = [] +tomli = [] +urllib3 = [] diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/poetry.toml b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/poetry.toml new file mode 100644 index 0000000..53b35d3 --- /dev/null +++ b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/poetry.toml @@ -0,0 +1,3 @@ +[virtualenvs] +create = true +in-project = true diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/pyproject.toml b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/pyproject.toml new file mode 100644 index 0000000..f36fda7 --- /dev/null +++ b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "shared" +version = "0.1.0" +description = "" +authors = ["Adam Tistler "] + +[tool.poetry.dependencies] +python = "^3.8" +requests = "^2.28.2" + +[tool.poetry.dev-dependencies] +pytest = "^7.0.1" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/main.tf b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/main.tf new file mode 100644 index 0000000..9207b75 --- /dev/null +++ b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/main.tf @@ -0,0 +1,21 @@ +provider "aws" { + region = "us-west-1" +} + +module "layer" { + source = "../../../../" + layer_name = "python-poetry-with-shared-package" + dependency_lock_file_path = "${path.module}/../../poetry.lock" + dependency_manager = "poetry" + use_ecr_image = true +} + +module "lambda_function" { + source = "terraform-aws-modules/lambda/aws" + function_name = "python-poetry-with-shared-package" + description = "Python poetry with shared package example" + handler = "index.lambda_handler" + runtime = "python3.8" + source_path = "./src/" + layers = [module.layer.arn] +} \ No newline at end of file diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/src/index.py b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/src/index.py new file mode 100644 index 0000000..617ff66 --- /dev/null +++ b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/src/index.py @@ -0,0 +1,4 @@ +from shared import myip + +def lambda_handler(event, context): + return myip.get() diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/src/shared b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/src/shared new file mode 120000 index 0000000..fde5761 --- /dev/null +++ b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/services/my_service/src/shared @@ -0,0 +1 @@ +../../../shared \ No newline at end of file diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/shared/__init__.py b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/shared/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/shared/myip.py b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/shared/myip.py new file mode 100644 index 0000000..a1da797 --- /dev/null +++ b/modules/lambda-layer-deps/examples/python-poetry-with-shared-module/shared/myip.py @@ -0,0 +1,4 @@ +import requests + +def get(): + return requests.get('https://api.ipify.org?format=json').json() diff --git a/modules/lambda-layer-deps/main.tf b/modules/lambda-layer-deps/main.tf index a277213..55f6ca2 100644 --- a/modules/lambda-layer-deps/main.tf +++ b/modules/lambda-layer-deps/main.tf @@ -14,6 +14,7 @@ data "external" "build" { dependency_manager = var.dependency_manager runtime = var.runtime dependency_lock_file = var.dependency_lock_file_path + use_ecr_image = var.use_ecr_image pre_package_commands = jsonencode(var.pre_package_commands) } } diff --git a/modules/lambda-layer-deps/package.py b/modules/lambda-layer-deps/package.py index 8a93432..3117fd0 100644 --- a/modules/lambda-layer-deps/package.py +++ b/modules/lambda-layer-deps/package.py @@ -115,7 +115,7 @@ def generate(self): class Workflow(ABC): def __init__(self, runtime, dependency_lock_file, dependency_file, docker_image=None, - pre_package_commands=[]): + pre_package_commands=[], use_ecr_image=False): self.runtime = runtime self.docker_image = docker_image self.pre_package_commands = pre_package_commands @@ -123,8 +123,11 @@ def __init__(self, runtime, dependency_lock_file, dependency_file, docker_image= self.package_dir = path.dirname(self.dependency_lock_file) self.dependency_file = path.join(self.package_dir, dependency_file) self.build_dir = './builds' + self.use_ecr_image = use_ecr_image if docker_image: self.docker_image = docker_image + elif self.use_ecr_image: + self.docker_image = 'public.ecr.aws/sam/build-{}'.format(self.runtime) else: self.docker_image = 'lambci/lambda:build-{}'.format(self.runtime) @@ -174,8 +177,8 @@ def install(self): class PoetryWorkflow(Workflow): - def __init__(self, runtime, dependency_lock_file, docker_image=None, pre_package_commands=[]): - super().__init__(runtime, dependency_lock_file, 'pyproject.toml', docker_image, pre_package_commands) + def __init__(self, runtime, dependency_lock_file, docker_image=None, pre_package_commands=[], use_ecr_image=False): + super().__init__(runtime, dependency_lock_file, 'pyproject.toml', docker_image, pre_package_commands, use_ecr_image) @property def pip_cmd(self): @@ -197,8 +200,8 @@ def get_runtime_dir(self, build_layer_dir): class NpmWorkflow(Workflow): - def __init__(self, runtime, dependency_lock_file, docker_image=None, pre_package_commands=[]): - super().__init__(runtime, dependency_lock_file, 'package.json', docker_image, pre_package_commands) + def __init__(self, runtime, dependency_lock_file, docker_image=None, pre_package_commands=[], use_ecr_image=False): + super().__init__(runtime, dependency_lock_file, 'package.json', docker_image, pre_package_commands, use_ecr_image) def install(self): install_cmd = f'cd /var/task && npm install --production' @@ -211,8 +214,8 @@ def get_runtime_dir(self, build_layer_dir): class YarnWorkflow(Workflow): - def __init__(self, runtime, dependency_lock_file, docker_image=None, pre_package_commands=[]): - super().__init__(runtime, dependency_lock_file, 'package.json', docker_image, pre_package_commands) + def __init__(self, runtime, dependency_lock_file, docker_image=None, pre_package_commands=[], use_ecr_image=False): + super().__init__(runtime, dependency_lock_file, 'package.json', docker_image, pre_package_commands, use_ecr_image) def install(self): install_cmd = f'cd /var/task && yarn install --production' @@ -238,7 +241,7 @@ def main(): archive_file = workflow( query["runtime"], query["dependency_lock_file"], query.get("docker_image"), - json.loads(query.get("pre_package_commands"))).run() + json.loads(query.get("pre_package_commands")), query.get("use_ecr_image")).run() print(json.dumps({'output_path': archive_file})) diff --git a/modules/lambda-layer-deps/variables.tf b/modules/lambda-layer-deps/variables.tf index 13bf1df..5cefb12 100644 --- a/modules/lambda-layer-deps/variables.tf +++ b/modules/lambda-layer-deps/variables.tf @@ -53,4 +53,10 @@ variable "pre_package_commands" { description = "Command to run on docker image before packaging step" type = list(string) default = [] +} + +variable "use_ecr_image" { + description = "By default this module will use lambci docker image, if you would like to use ECR lambda images set this option to true (recommended)" + type = bool + default = false } \ No newline at end of file