Module Terraform, qui crée presque toutes les ressources AWS Lambda soutenues ainsi que la prise en charge de la construction et de l'emballage des dépendances Lambda requises pour les fonctions et les couches.
Ce module Terraform est la partie de Serverless.TF Framework, qui vise à simplifier toutes les opérations lorsque vous travaillez avec le serveur sans serveur dans Terraform:
serverless.tf
comme la passerelle API HTTP (voir les exemples). module "lambda_function" {
source = " terraform-aws-modules/lambda/aws "
function_name = " my-lambda1 "
description = " My awesome lambda function "
handler = " index.lambda_handler "
runtime = " python3.12 "
source_path = " ../src/lambda-function1 "
tags = {
Name = " my-lambda1 "
}
}
module "lambda_function" {
source = " terraform-aws-modules/lambda/aws "
function_name = " lambda-with-layer "
description = " My awesome lambda function "
handler = " index.lambda_handler "
runtime = " python3.12 "
publish = true
source_path = " ../src/lambda-function1 "
store_on_s3 = true
s3_bucket = " my-bucket-id-with-lambda-builds "
layers = [
module . lambda_layer_s3 . lambda_layer_arn ,
]
environment_variables = {
Serverless = " Terraform "
}
tags = {
Module = " lambda-with-layer "
}
}
module "lambda_layer_s3" {
source = " terraform-aws-modules/lambda/aws "
create_layer = true
layer_name = " lambda-layer-s3 "
description = " My amazing lambda layer (deployed from S3) "
compatible_runtimes = [ " python3.12 " ]
source_path = " ../src/lambda-layer "
store_on_s3 = true
s3_bucket = " my-bucket-id-with-lambda-builds "
}
module "lambda_function_existing_package_local" {
source = " terraform-aws-modules/lambda/aws "
function_name = " my-lambda-existing-package-local "
description = " My awesome lambda function "
handler = " index.lambda_handler "
runtime = " python3.12 "
create_package = false
local_existing_package = " ../existing_package.zip "
}
Si vous souhaitez gérer le code de fonction et les ressources d'infrastructure (telles que les autorisations IAM, les politiques, les événements, etc.) dans des flux distincts (par exemple, différents référentiels, équipes, pipelines CI / CD).
Désactivez le suivi du code source pour désactiver les déploiements (et les rollbacks) à l'aide du module en définissant ignore_source_code_hash = true
et déployez une fonction factice .
Lorsque l'infrastructure et la fonction factice sont déployées, vous pouvez utiliser un outil externe pour mettre à jour le code source de la fonction (par exemple, en utilisant AWS CLI) et continuer à utiliser ce module via Terraform pour gérer l'infrastructure.
Sachez que les changements dans la valeur local_existing_package
peuvent déclencher le déploiement via Terraform.
module "lambda_function_externally_managed_package" {
source = " terraform-aws-modules/lambda/aws "
function_name = " my-lambda-externally-managed-package "
description = " My lambda function code is deployed separately "
handler = " index.lambda_handler "
runtime = " python3.12 "
create_package = false
local_existing_package = " ./lambda_functions/code.zip "
ignore_source_code_hash = true
}
Notez que ce module ne copie pas les packages prédéfinis en seau S3. Ce module ne peut stocker que des packages qu'il construit localement et dans le seau S3.
locals {
my_function_source = " ../path/to/package.zip "
}
resource "aws_s3_bucket" "builds" {
bucket = " my-builds "
acl = " private "
}
resource "aws_s3_object" "my_function" {
bucket = aws_s3_bucket . builds . id
key = " ${ filemd5 (local . my_function_source ) } .zip "
source = local . my_function_source
}
module "lambda_function_existing_package_s3" {
source = " terraform-aws-modules/lambda/aws "
function_name = " my-lambda-existing-package-local "
description = " My awesome lambda function "
handler = " index.lambda_handler "
runtime = " python3.12 "
create_package = false
s3_existing_package = {
bucket = aws_s3_bucket.builds.id
key = aws_s3_object.my_function.id
}
}
module "lambda_function_container_image" {
source = " terraform-aws-modules/lambda/aws "
function_name = " my-lambda-existing-package-local "
description = " My awesome lambda function "
create_package = false
image_uri = " 132367819851.dkr.ecr.eu-west-1.amazonaws.com/complete-cow:1.0 "
package_type = " Image "
}
module "lambda_layer_local" {
source = " terraform-aws-modules/lambda/aws "
create_layer = true
layer_name = " my-layer-local "
description = " My amazing lambda layer (deployed from local) "
compatible_runtimes = [ " python3.12 " ]
source_path = " ../fixtures/python-app1 "
}
module "lambda_layer_s3" {
source = " terraform-aws-modules/lambda/aws "
create_layer = true
layer_name = " my-layer-s3 "
description = " My amazing lambda layer (deployed from S3) "
compatible_runtimes = [ " python3.12 " ]
source_path = " ../fixtures/python-app1 "
store_on_s3 = true
s3_bucket = " my-bucket-id-with-lambda-builds "
}
Assurez-vous que vous déploiez les fonctions lambda @ edge dans la région américaine de l'Est (N. Virginia) ( us-east-1
). Voir les exigences et les restrictions sur les fonctions de lambda.
module "lambda_at_edge" {
source = " terraform-aws-modules/lambda/aws "
lambda_at_edge = true
function_name = " my-lambda-at-edge "
description = " My awesome lambda@edge function "
handler = " index.lambda_handler "
runtime = " python3.12 "
source_path = " ../fixtures/python-app1 "
tags = {
Module = " lambda-at-edge "
}
}
module "lambda_function_in_vpc" {
source = " terraform-aws-modules/lambda/aws "
function_name = " my-lambda-in-vpc "
description = " My awesome lambda function "
handler = " index.lambda_handler "
runtime = " python3.12 "
source_path = " ../fixtures/python-app1 "
vpc_subnet_ids = module . vpc . intra_subnets
vpc_security_group_ids = [ module . vpc . default_security_group_id ]
attach_network_policy = true
}
module "vpc" {
source = " terraform-aws-modules/vpc/aws "
name = " my-vpc "
cidr = " 10.10.0.0/16 "
# Specify at least one of: intra_subnets, private_subnets, or public_subnets
azs = [ " eu-west-1a " , " eu-west-1b " , " eu-west-1c " ]
intra_subnets = [ " 10.10.101.0/24 " , " 10.10.102.0/24 " , " 10.10.103.0/24 " ]
}
Il existe 6 moyens pris en charge d'attacher les politiques IAM au rôle IAM utilisé par la fonction Lambda:
policy_json
- JSON String ou Heredoc, lorsque attach_policy_json = true
.policy_jsons
- Liste des chaînes JSON ou Heredoc, lorsque attach_policy_jsons = true
et number_of_policy_jsons > 0
.policy
- ARN de la politique IAM existante, lorsque attach_policy = true
.policies
- Liste des ARN des stratégies IAM existantes, lorsque attach_policies = true
et number_of_policies > 0
.policy_statements
- Carte des cartes pour définir les instructions IAM qui seront générées en tant que politique IAM. Nécessite attach_policy_statements = true
. Voir examples/complete
pour plus d'informations.assume_role_policy_statements
- Carte des cartes pour définir les instructions IAM qui seront générées en tant que politique IAM pour assumer le rôle de fonction Lambda (relation de confiance). Voir examples/complete
pour plus d'informations. Les autorisations de Lambda doivent être spécifiées pour permettre à certaines ressources d'invoquer la fonction Lambda.
module "lambda_function" {
source = " terraform-aws-modules/lambda/aws "
# ...omitted for brevity
allowed_triggers = {
Config = {
principal = " config.amazonaws.com "
principal_org_id = " o-abcdefghij "
}
APIGatewayAny = {
service = " apigateway "
source_arn = " arn:aws:execute-api:eu-west-1:135367859851:aqnku8akd0/*/*/* "
},
APIGatewayDevPost = {
service = " apigateway "
source_arn = " arn:aws:execute-api:eu-west-1:135367859851:aqnku8akd0/dev/POST/* "
},
OneRule = {
principal = " events.amazonaws.com "
source_arn = " arn:aws:events:eu-west-1:135367859851:rule/RunDaily "
}
}
}
Parfois, vous devez avoir un moyen de créer des ressources conditionnellement, mais Terraform ne permet pas d'utiliser le count
à l'intérieur du bloc module
, donc la solution consiste à spécifier des arguments create
.
module "lambda" {
source = " terraform-aws-modules/lambda/aws "
create = false # to disable all resources
create_package = false # to control build package process
create_function = false # to control creation of the Lambda Function and related resources
create_layer = false # to control creation of the Lambda Layer and related resources
create_role = false # to control creation of the IAM role and policies required for Lambda Function
attach_cloudwatch_logs_policy = false
attach_dead_letter_policy = false
attach_network_policy = false
attach_tracing_policy = false
attach_async_event_policy = false
# ... omitted
}
C'est l'une des parties les plus compliquées par le module et normalement vous n'avez pas à connaître les internes.
package.py
est un script python qui le fait. Assurez-vous que Python 3.6 ou plus récent est installé. Les fonctions principales du script sont de générer un nom de fichier de zip-archive en fonction du contenu des fichiers, de vérifier si Zip-Archive a déjà été créé et de créer un zip-archive uniquement lorsqu'il est nécessaire (pendant apply
, pas plan
) .
Le hachage de zip-archive créé avec le même contenu des fichiers est toujours identique, ce qui empêche les dates de force inutiles des ressources lambda à moins que le contenu ne modifie. Si vous avez besoin d'avoir des noms de fichiers différents pour le même contenu, vous pouvez spécifier un argument de chaîne supplémentaire hash_extra
.
Lorsque vous appelez ce module plusieurs fois dans une seule exécution pour créer des packages avec la même source_path
, les archives Zip seront corrompues en raison d'écrits simultanés dans le même fichier. Il existe deux solutions - définissez des valeurs différentes pour hash_extra
pour créer des archives différentes, ou créer un package une fois à l'extérieur (en utilisant ce module), puis passer l'argument local_existing_package
pour créer d'autres ressources lambda.
La construction et l'emballage ont été historiquement difficiles à déboguer (en particulier avec TerraForm), nous avons donc fait un effort pour faciliter les informations de débogage. Il y a 3 niveaux de débogage différents: DEBUG
- pour voir uniquement ce qui se passe pendant DEBUG3
phase de planification et DUMP_ENV
un filtrage de contenu de fichier zip en cas de modèles appliqués, DEBUG2
- Pour voir plus Voir toutes les valeurs de journalisation et variables Env (soyez prudent partageant vos variables Env car elles peuvent contenir des secrets!).
L'utilisateur peut spécifier le niveau de débogage comme ceci:
export TF_LAMBDA_PACKAGE_LOG_LEVEL=DEBUG2
terraform apply
L'utilisateur peut activer les commentaires dans les chaînes Heredoc dans patterns
qui peuvent être utiles dans certaines situations. Pour ce faire, définissez cette variable d'environnement:
export TF_LAMBDA_PACKAGE_PATTERN_COMMENTS=true
terraform apply
Vous pouvez spécifier source_path
de diverses façons d'atteindre la flexibilité souhaitée lors de la construction de packages de déploiement localement ou dans Docker. Vous pouvez utiliser des chemins absolus ou relatifs. Si vous avez placé des fichiers Terraform dans les sous-répertoires, notez que les chemins relatifs sont spécifiés à partir du répertoire où terraform plan
est exécuté et non l'emplacement de votre fichier Terraform.
Notez que, lors de la construction localement, les fichiers ne copient pas dans les répertoires source lors de la fabrication de packages, nous utilisons des expressions régulières Fast Python pour trouver des fichiers et répertoires correspondants, ce qui rend les emballages très rapides et faciles à comprendre.
Lorsque source_path
est défini sur une chaîne, le contenu de ce chemin sera utilisé pour créer un package de déploiement en tant que:
source_path = "src/function1"
Lorsque source_path
est défini sur une liste de répertoires, le contenu de chacun sera pris et une archive sera créée.
Il s'agit du moyen le plus complet de créer un package de déploiement à partir de plusieurs sources avec plusieurs dépendances. Cet exemple montre certaines des options disponibles (voir des exemples / emballage de construction et des exemples / runtimes pour en savoir plus):
source_path = [
" src/main-source " ,
" src/another-source/index.py " ,
{
path = " src/function1-dep " ,
patterns = [
" !.*/.* \ .txt " , # Skip all txt files recursively
]
}, {
path = " src/python-app1 " ,
pip_requirements = true ,
pip_tmp_dir = " /tmp/dir/location "
prefix_in_zip = " foo/bar1 " ,
}, {
path = " src/python-app2 " ,
pip_requirements = " requirements-large.txt " ,
patterns = [
" !vendor/colorful-0.5.4.dist-info/RECORD " ,
" !vendor/colorful-.+.dist-info/.* " ,
" !vendor/colorful/__pycache__/?.* " ,
]
}, {
path = " src/nodejs14.x-app1 " ,
npm_requirements = true ,
npm_tmp_dir = " /tmp/dir/location "
prefix_in_zip = " foo/bar1 " ,
}, {
path = " src/python-app3 " ,
commands = [
" npm install " ,
" :zip "
],
patterns = [
" !.*/.* \ .txt " , # Skip all txt files recursively
" node_modules/.+ " , # Include all node_modules
],
}, {
path = " src/python-app3 " ,
commands = [ " go build " ],
patterns = << END
bin/.*
abc/def/.*
END
}
]
Peu de notes:
python
ou nodejs
, le processus de construction créera automatiquement les dépendances Python et Nodejs si requirements.txt
ou package.json
se trouvent dans le dossier source. Si vous souhaitez personnaliser ce comportement, veuillez utiliser la notation de l'objet comme expliqué ci-dessous.path
sont facultatifs.patterns
- Liste des noms de fichiers Regex Python doit satisfaire. La valeur par défaut est "Inclure tout" qui est égal aux patterns = [".*"]
. Cela peut également être spécifié en tant que chaîne multiline heredoc (aucun commentaire autorisé). Quelques exemples de modèles valides:commands
et chaîne plusieurs commandes, seul le code de sortie de la dernière commande sera vérifié pour le succès. Si vous préférez échouer rapidement, démarrez les commandes avec l'option bash set -e
ou PowerShell Option $ErrorActionPreference="Stop"
!. * /. * .txt # Filter all txt files recursively
node_modules/. * # Include empty dir or with a content if it exists
node_modules/.+ # Include full non empty node_modules dir with its content
node_modules/ # Include node_modules itself without its content
# It's also a way to include an empty dir if it exists
node_modules # Include a file or an existing dir only
!abc/. * # Filter out everything in an abc folder
abc/def/. * # Re-include everything in abc/def sub folder
!abc/def/hgk/. * # Filter out again in abc/def/hgk sub folder
commands
- Liste des commandes à exécuter. S'il est spécifié, cet argument remplace pip_requirements
et npm_requirements
.:zip [source] [destination]
est une commande spéciale qui crée le contenu du répertoire de travail actuel (premier argument) et le place à l'intérieur du chemin (deuxième argument).pip_requirements
- contrôle s'il faut exécuter pip install
. Défini sur false
pour désactiver cette fonctionnalité, true
pour exécuter pip install
avec requirements.txt
trouvé dans path
. Ou défini sur un autre nom de fichier que vous souhaitez utiliser à la place. Lorsque source_path
est passé sous forme de chaîne contenant un chemin (et non comme une liste de cartes) et que requirements.txt
sont présentes, pip install
est automatiquement exécutée.pip_tmp_dir
- Définissez le répertoire de base pour créer le répertoire temporaire des installations PIP. Peut être utile pour Docker dans Docker Builds.poetry_install
- contrôle s'il faut exécuter poetry export
et pip install
. Défini sur false
pour désactiver cette fonctionnalité, true
pour exécuter poetry export
avec pyproject.toml
et poetry.lock
trouvé dans path
. Lorsque source_path
est passé en tant que chaîne contenant un chemin (et non comme une liste de cartes), et pyproject.toml
avec une poetry
système de construction est présent, poetry export
et pip install
est automatiquement exécuté.poetry_export_extra_args
- Une liste d'arguments de poésie supplémentaires à ajouter à la commande de poésie d'exportation de poésienpm_requirements
- CONTRÔLE L'exécution npm install
. Défini sur false
pour désactiver cette fonctionnalité, true
pour exécuter npm install
avec package.json
trouvé dans path
. Ou défini sur un autre nom de fichier que vous souhaitez utiliser à la place.npm_tmp_dir
- Définissez le répertoire de base pour réaliser le répertoire temporaire des installations NPM. Peut être utile pour Docker dans Docker Builds.prefix_in_zip
- Si spécifié, sera utilisé comme préfixe dans Zip-Archive. Par défaut, tout s'installe dans la racine de Zip-Archive.Si votre fonction ou couche Lambda utilise certaines dépendances, vous pouvez les construire dans Docker et les faire inclure dans le package de déploiement. Voici comment vous pouvez le faire:
build_in_docker = true
docker_file = "src/python-app1/docker/Dockerfile"
docker_build_root = "src/python-app1/docker"
docker_image = "public.ecr.aws/sam/build-python"
runtime = "python3.12" # Setting runtime is required when building package in Docker and Lambda Layer resource.
À l'aide de ce module, vous pouvez installer des dépendances à partir d'hôtes privés. Pour ce faire, vous avez besoin d'un agent SSH avant:
docker_with_ssh_agent = true
Notez que par défaut, le docker_image
utilisé provient du registre public.ecr.aws/sam/
, et sera basé sur le runtime
que vous spécifiez. En d'autres termes, si vous spécifiez un runtime de python3.12
et ne spécifiez pas docker_image
, alors le docker_image
se résoudra à public.ecr.aws/sam/build-python3.12
. Cela garantit que par défaut, l' runtime
est disponible dans le conteneur Docker.
Si vous remplacez docker_image
, assurez-vous de garder l'image en synchronisation avec votre runtime
. Pendant la phase du plan, lors de l'utilisation de Docker, il n'y a pas de vérification que l' runtime
est disponible pour créer le package. Cela signifie que si vous utilisez une image qui n'a pas le temps d'exécution, le plan réussira, mais que l'application échouera.
Pour ajouter de la flexibilité lors de la construction dans Docker, vous pouvez transmettre n'importe quel nombre d'options supplémentaires dont vous avez besoin (voir la référence Docker Exécuter pour les options disponibles):
docker_additional_options = [
" -e " , " MY_ENV_VAR='My environment variable value' " ,
" -v " , " /local:/docker-vol " ,
]
Pour remplacer le point d'entrée Docker lors de la construction dans Docker, définissez docker_entrypoint
:
docker_entrypoint = " /entrypoint/entrypoint.sh "
Le point d'entrée doit mapper sur un chemin dans votre conteneur, vous devez donc créer votre propre image qui contient le point d'entrée ou le mapper dans un fichier de l'hôte en montant un volume (voir passer des options de docker supplémentaires).
Par défaut, ce module crée un package de déploiement et l'utilise pour créer ou mettre à jour la fonction lambda ou la couche Lambda.
Parfois, vous pouvez séparer la construction du package de déploiement (par exemple, pour compiler et installer des dépendances) à partir du déploiement d'un package en deux étapes distinctes.
Lors de la création d'archives localement en dehors de ce module, vous devez définir create_package = false
puis argumenter local_existing_package = "existing_package.zip"
. Alternativement, vous préférez peut-être garder vos packages de déploiement dans le seau S3 et leur fournir une référence comme ceci:
create_package = false
s3_existing_package = {
bucket = " my-bucket-with-lambda-builds "
key = " existing_package.zip "
}
Cela peut être implémenté en deux étapes: téléchargez le fichier localement à l'aide de Curl et passe le package de déploiement en tant qu'argument local_existing_package
.
locals {
package_url = " https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-lambda/master/examples/fixtures/python-zip/existing_package.zip "
downloaded = " downloaded_package_ ${ md5 (local . package_url ) } .zip "
}
resource "null_resource" "download_package" {
triggers = {
downloaded = local.downloaded
}
provisioner "local-exec" {
command = " curl -L -o ${ local . downloaded } ${ local . package_url } "
}
}
data "null_data_source" "downloaded_package" {
inputs = {
id = null_resource.download_package.id
filename = local.downloaded
}
}
module "lambda_function_existing_package_from_remote_url" {
source = " terraform-aws-modules/lambda/aws "
function_name = " my-lambda-existing-package-local "
description = " My awesome lambda function "
handler = " index.lambda_handler "
runtime = " python3.12 "
create_package = false
local_existing_package = data . n ull_data_source . downloaded_package . outputs [ " filename " ]
}
AWS SAM CLI est un outil open source qui aide les développeurs à initier, créer, tester et déployer des applications sans serveur. L'outil SAM CLI prend en charge les applications Terraform.
Sam CLI fournit deux façons de tester: les tests locaux et les tests sur le cloud (accélérer).
En utilisant SAM CLI, vous pouvez invoquer les fonctions lambda définies dans l'application Terraform localement à l'aide de la commande SAM Local Invoke, fournissant l'adresse de terraform de fonction ou le nom de la fonction, et pour définir le hook-name
sur terraform
pour dire à Sam CLI que le projet sous-jacent est une application Terraform.
Vous pouvez exécuter la commande sam local invoke
à partir de votre répertoire racine d'application Terraform comme suit:
sam local invoke --hook-name terraform module.hello_world_function.aws_lambda_function.this[0]
Vous pouvez également transmettre un événement à votre fonction Lambda ou écraser ses variables d'environnement. Vérifiez ici pour plus d'informations.
Vous pouvez également invoquer votre fonction lambda en mode de débogage et parcourir votre code source de fonction lambda localement dans votre éditeur préféré. Vérifiez ici pour plus d'informations.
Vous pouvez utiliser AWS Sam CLI pour tester rapidement votre application sur votre compte de développement AWS. En utilisant SAM Accelerate, vous pourrez développer vos fonctions Lambda localement, et une fois que vous enregistrez vos mises à jour, SAM CLI mettra à jour votre compte de développement avec les fonctions Lambda mises à jour. Ainsi, vous pouvez le tester sur le cloud, et s'il y a un bogue, vous pouvez rapidement mettre à jour le code et Sam CLI s'occupera de le pousser vers le cloud. Vérifiez ici plus d'informations sur Sam Accelerate.
Vous pouvez exécuter la commande sam sync
à partir de votre répertoire racine d'application Terraform comme suit:
sam sync --hook-name terraform --watch
En règle générale, les mises à jour de la ressource de la fonction lambda lorsque le code source change. Si publish = true
est spécifié, une nouvelle version de la fonction lambda sera également créée.
La fonction lambda publiée peut être invoquée à l'aide de numéro de version ou en utilisant $LATEST
. Il s'agit du moyen de déploiement le plus simple qui ne nécessite aucun outil ou service supplémentaire.
Afin de effectuer des déploiements contrôlés (roulement, canari, rollbacks) des fonctions lambda, nous devons utiliser des alias de fonction lambda.
En termes simples, Lambda Alias est comme un pointeur vers une version de la fonction lambda (lorsque le déploiement est terminé), soit sur deux versions pondérées de la fonction lambda (pendant le déploiement de roulement ou de canari).
Une fonction Lambda peut être utilisée dans plusieurs alias. L'utilisation d'alias donne un grand contrôle de la version déployée lors de plusieurs environnements.
Il y a un module d'alias, qui simplifie le travail avec ALIAS (créer, gérer les configurations, les mises à jour, etc.). Voir Exemples / alias pour diverses cas d'utilisation Comment les alias peuvent être configurés et utilisés.
Il existe un module de déploiement, qui crée des ressources requises pour effectuer des déploiements à l'aide d'AWS CodeDeploy. Il crée également le déploiement et attend l'achèvement. Voir Exemples / Déploiement pour le processus complet de construction / mise à jour / déploiement de bout en bout.
Terraform Cloud, Terraform Enterprise et de nombreux autres SaaS pour l'exécution de Terraform n'ont pas préinstallé Python sur les travailleurs. Vous devrez fournir une image docker alternative avec Python installé pour pouvoir y utiliser ce module.
Q1: Pourquoi le package de déploiement ne recréait pas chaque fois que je change quelque chose? Ou pourquoi le package de déploiement est recréé à chaque fois, mais le contenu n'a pas été modifié?
Réponse: Il peut y avoir plusieurs raisons liées aux exécutions simultanées ou au hachage de contenu. Parfois, des changements se sont produits à l'intérieur de la dépendance qui n'est pas utilisé pour calculer le hachage de contenu. Ou plusieurs packages créent en même temps à partir des mêmes sources. Vous pouvez le forcer en définissant la valeur de
hash_extra
à des valeurs distinctes.
Q2: Comment forcer le package de déploiement recréant?
Réponse: supprimez un zip-archive existant du répertoire
builds
ou apportez un changement dans votre code source. S'il n'y a pas de zip-archive pour le hachage de contenu actuel, il sera recréé pendantterraform apply
.
Q3: null_resource.archive[0] must be replaced
Réponse: Cela signifie probablement que Zip-Archive a été déployé, mais est actuellement absent localement, et il doit être recréé localement. Lorsque vous rencontrez ce problème pendant le processus CI / CD (où l'espace de travail est propre) ou à partir de plusieurs espaces de travail, vous pouvez définir la variable d'environnement
TF_RECREATE_MISSING_LAMBDA_PACKAGE=false
ou passerrecreate_missing_package = false
en tant que paramètre au module et exécuterterraform apply
. Alternativement, vous pouvez transmettretrigger_on_package_timestamp = false
en tant que paramètre pour ignorer l'horodatage du fichier lors de la décision de créer l'archive ou non.
Q4: Que signifie cette erreur - "We currently do not support adding policies for $LATEST."
?
Réponse: Lorsque la fonction lambda est créée avec
publish = true
la nouvelle version est automatiquement augmentée et qu'un identifiant qualifié (numéro de version) devient disponible et sera utilisé lors de la définition des autorisations Lambda.Lorsque
publish = false
(par défaut), seul l'identifiant non qualifié ($LATEST
) est disponible, ce qui conduit à l'erreur.La solution consiste à désactiver la création des autorisations de lambda pour la version actuelle en définissant
create_current_version_allowed_triggers = false
, soit pour permettre la publication de la fonction lambda (publish = true
).
builds
est souvent absent.Nom | Version |
---|---|
terraform | > = 1.0 |
AWS | > = 5,70 |
externe | > = 1.0 |
locale | > = 1.0 |
nul | > = 2.0 |
Nom | Version |
---|---|
AWS | > = 5,70 |
externe | > = 1.0 |
locale | > = 1.0 |
nul | > = 2.0 |
Pas de modules.
Nom | Taper |
---|---|
aws_cloudwatch_log_group.lambda | ressource |
aws_iam_policy.additional_inline | ressource |
aws_iam_policy.additional_json | ressource |
aws_iam_policy.additional_jsons | ressource |
aws_iam_policy.async | ressource |
aws_iam_policy.dead_letter | ressource |
aws_iam_policy.logs | ressource |
aws_iam_policy.tracture | ressource |
aws_iam_policy.vpc | ressource |
aws_iam_role.lambda | ressource |
aws_iam_role_policy_attachment.additional_inline | ressource |
aws_iam_role_policy_attachment.additional_json | ressource |
aws_iam_role_policy_attachment.additional_jsons | ressource |
aws_iam_role_policy_attachment.additional_many | ressource |
aws_iam_role_policy_attachment.additional_one | ressource |
aws_iam_role_policy_attachment.async | ressource |
aws_iam_role_policy_attachment.dead_letter | ressource |
aws_iam_role_policy_attachment.logs | ressource |
aws_iam_role_policy_attachment.tracture | ressource |
aws_iam_role_policy_attachment.vpc | ressource |
aws_lambda_event_source_mapping. | ressource |
aws_lambda_function.si | ressource |
aws_lambda_function_event_invoke_config. | ressource |
aws_lambda_function_url. | ressource |
aws_lambda_layer_version. | ressource |
aws_lambda_permission.current_version_triggers | ressource |
aws_lambda_permission.unqualified_alias_triggers | ressource |
aws_lambda_provisioned_concurrency_config.current_version | ressource |
aws_s3_object.lambda_package | ressource |
local_file.archive_plan | ressource |
null_resource.archive | ressource |
null_resource.sam_metadata_aws_lambda_function | ressource |
null_resource.sam_metadata_aws_lambda_layer_version | ressource |
aws_arn.log_group_arn | source de données |
aws_caller_identity.current | source de données |
aws_cloudwatch_log_group.lambda | source de données |
aws_iam_policy.tracture | source de données |
aws_iam_policy.vpc | source de données |
aws_iam_policy_document.additional_inline | source de données |
aws_iam_policy_document.assume_role | source de données |
aws_iam_policy_document.async | source de données |
aws_iam_policy_document.dead_letter | source de données |
aws_iam_policy_document.logs | source de données |
aws_partition.current | source de données |
aws_region.current | source de données |
external_external.archive_prepare | source de données |
Nom | Description | Taper | Défaut | Requis |
---|---|---|---|---|
ALLÉMENT | Carte des déclencheurs autorisés pour créer des autorisations Lambda | map(any) | {} | Non |
architectures | Architecture de jeu d'instructions pour votre fonction lambda. Les valeurs valides sont ["x86_64"] et ["ARM64"]. | list(string) | null | Non |
artefacts_dir | Nom du répertoire où les artefacts doivent être stockés | string | "builds" | Non |
PUSUME_ROLE_POLICY_STATSTATION | Carte des déclarations de politique dynamique pour assumer le rôle de fonction Lambda (relation de confiance) | any | {} | Non |
attach_async_event_policy | Contrôle si la politique d'événement asynchrone devrait être ajoutée au rôle IAM pour la fonction lambda | bool | false | Non |
attach_cloudwatch_logs_policy | Contrôle si la stratégie des journaux CloudWatch devrait être ajoutée au rôle IAM pour la fonction lambda | bool | true | Non |
attach_create_log_group_permission | Contrôles s'il faut ajouter l'autorisation du groupe de journaux à la stratégie des journaux CloudWatch | bool | true | Non |
attach_dead_letter_policy | Contrôle si la politique de notification des lettres mortes SNS / SQS doit être ajoutée au rôle IAM pour la fonction lambda | bool | false | Non |
attach_network_policy | Contrôle si la stratégie VPC / réseau doit être ajoutée au rôle IAM pour la fonction lambda | bool | false | Non |
attach_policies | Contrôle si la liste des politiques doit être ajoutée au rôle IAM pour la fonction Lambda | bool | false | Non |
attach_policy | Contrôle si la politique doit être ajoutée au rôle IAM pour la fonction lambda | bool | false | Non |
attach_policy_json | Contrôle si Policy_json doit être ajouté au rôle IAM pour la fonction Lambda | bool | false | Non |
attach_policy_jsons | Contrôle si Policy_Jsons doit être ajouté au rôle IAM pour la fonction Lambda | bool | false | Non |
attach_policy_statements | Contrôle si Policy_statements doit être ajouté au rôle IAM pour la fonction Lambda | bool | false | Non |
attach_tracing_policy | Contrôle si la politique de traçage des rayons X doit être ajoutée au rôle IAM pour la fonction lambda | bool | false | Non |
Autorisation_Type | Le type d'authentification que l'URL de la fonction lambda utilise. Réglé sur «aws_iam» pour restreindre l'accès aux utilisateurs IAM authentifiés uniquement. Définissez «aucun» pour contourner l'authentification IAM et créer un point de terminaison public. | string | "NONE" | Non |
build_in_docker | S'il faut construire des dépendances dans Docker | bool | false | Non |
cloudwatch_logs_kms_key_id | L'ARN de la touche KMS à utiliser lors du chiffrement des données de journal. | string | null | Non |
cloudwatch_logs_log_group_class | Spécifié la classe de journal du groupe de journaux. Les valeurs possibles sont les suivantes: STANDARD ou INFREQUENT_ACCESS | string | null | Non |
cloudwatch_logs_retention_in_days | Spécifie le nombre de jours que vous souhaitez conserver les événements de journal dans le groupe de journaux spécifié. Les valeurs possibles sont: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827 et 3653. | number | null | Non |
cloudwatch_logs_skip_destroy | S'il faut conserver le groupe de journaux (et tous les journaux qu'il peut contenir) au moment de détruire. | bool | false | Non |
cloudwatch_logs_tags | Une carte des balises à attribuer à la ressource. | map(string) | {} | Non |
code_signing_config_arn | Nom de ressource Amazon (ARN) pour une configuration de signature de code | string | null | Non |
compatible_architectures | Une liste des architectures Lambda Cose est compatible. Actuellement, X86_64 et ARM64 peuvent être spécifiés. | list(string) | null | Non |
compatible_runtimes | Une liste des temps d'exécution avec laquelle cette couche est compatible. Jusqu'à 5 temps d'exécution peuvent être spécifiés. | list(string) | [] | Non |
cors | Paramètres CORS à utiliser par l'URL de la fonction lambda | any | {} | Non |
créer | Contrôle si les ressources doivent être créées | bool | true | Non |
create_async_event_config | Contrôle si la configuration de l'événement asynchrone pour la fonction / alias lambda doit être créée | bool | false | Non |
create_current_version_allowed_triggers | Il faut autoriser des déclencheurs sur la version actuelle de la fonction lambda (cela révèlera les autorisations de la version précédente car Terraform ne gère que les ressources actuelles) | bool | true | Non |
create_current_version_async_event_config | L'avoir permettre la configuration de l'événement asynchrone sur la version actuelle de la fonction lambda (cela révèlera les autorisations de la version précédente car Terraform gère uniquement les ressources actuelles) | bool | true | Non |
create_function | Contrôle si la ressource de fonction lambda doit être créée | bool | true | Non |
create_lambda_function_url | Contrôle si la ressource URL de la fonction lambda doit être créée | bool | false | Non |
create_layer | Contrôle si la ressource de couche Lambda doit être créée | bool | false | Non |
create_package | Contrôle si le package lambda doit être créé | bool | true | Non |
create_role | Contrôle si le rôle IAM pour la fonction lambda doit être créé | bool | true | Non |
create_sam_metadata | Contrôle si la ressource nulle des métadonnées SAM doit être créée | bool | false | Non |
create_unqualified_alias_allowed_triggers | Que ce soit pour permettre des déclencheurs sur des alias non qualifiés pointant vers $ la dernière version | bool | true | Non |
create_unqualified_alias_async_event_config | L'avoir permettre une configuration d'événement asynchrone sur un alias non qualifié pointant vers $ la dernière version | bool | true | Non |
create_unqualified_alias_lambda_function_url | L'avoir utilisé des alias non qualifiés pointant vers $ la dernière version dans URL de la fonction lambda | bool | true | Non |
Dead_letter_target_arn | L'ARN d'un sujet SNS ou une file d'attente SQS pour informer lorsqu'une invocation échoue. | string | null | Non |
description | Description de votre fonction (ou couche) de lambda | string | "" | Non |
destination_on_failure | Nom de la ressource Amazon (ARN) de la ressource de destination pour les invocations asynchrones ratées | string | null | Non |
Destination_on_success | Nom de la ressource Amazon (ARN) de la ressource de destination pour les invocations asynchrones réussies | string | null | Non |
docker_additional_options | Options supplémentaires pour passer à la commande docker run (par exemple pour définir des variables d'environnement, des volumes, etc.) | list(string) | [] | Non |
docker_build_root | Racine dir où construire dans docker | string | "" | Non |
docker_entrypoint | Chemin vers le point d'entrée Docker à utiliser | string | null | Non |
docker_file | Chemin vers un Dockerfile lors de la construction dans Docker | string | "" | Non |
docker_image | Image docker à utiliser pour la construction | string | "" | Non |
docker_pip_cache | Que ce soit pour monter un dossier de cache PIP partagé dans un environnement Docker ou non | any | null | Non |
docker_with_ssh_agent | Que ce soit pour passer SSH_Auth_Sock dans un environnement Docker ou non | bool | false | Non |
environnement_variables | Une carte qui définit les variables d'environnement pour la fonction lambda. | map(string) | {} | Non |
ephémeral_storage_size | Quantité de stockage éphémère (/ TMP) dans MB Votre fonction Lambda peut utiliser au moment de l'exécution. Valeur valide entre 512 Mb et 10 240 Mo (10 Go). | number | 512 | Non |
event_source_mapping | Carte de la cartographie des sources d'événements | any | {} | Non |
file_system_arn | Le nom de ressource Amazon (ARN) du point d'accès Amazon EFS qui donne accès au système de fichiers. | string | null | Non |
file_system_local_mount_path | Le chemin d'accès où la fonction peut accéder au système de fichiers, en commençant par / mnt /. | string | null | Non |
function_name | Un nom unique pour votre fonction lambda | string | "" | Non |
function_tags | Une carte des balises à affecter uniquement à la fonction lambda | map(string) | {} | Non |
maître | Point d'entrée de la fonction lambda dans votre code | string | "" | Non |
hash_extra | La chaîne à ajouter dans la fonction de hachage. Utile lors de la construction du même chemin source pour différentes fonctions. | string | "" | Non |
ignore_source_code_hash | Il faut ignorer les modifications du hachage du code source de la fonction. Définissez TRUE si vous gérez séparément les déploiements d'infrastructure et de code. | bool | false | Non |
image_config_command | Le CMD pour l'image Docker | list(string) | [] | Non |
image_config_entry_point | Le point d'entrée de l'image docker | list(string) | [] | Non |
image_config_working_directory | Le répertoire de travail pour l'image docker | string | null | Non |
image_uri | L'image ECR URI contenant le package de déploiement de la fonction. | string | null | Non |
invoke_mode | Invoquez le mode de l'URL de la fonction lambda. Les valeurs valides sont tamponnées (par défaut) et Response_stream. | string | null | Non |
ipv6_allowed_for_dual_stack | Permet un trafic IPv6 sortant sur les fonctions VPC qui sont connectées à des sous-réseaux à double pile | bool | null | Non |
kms_key_arn | La touche ARN de KMS à utiliser par votre fonction lambda | string | null | Non |
lambda_at_edge | Définissez ceci sur true si vous utilisez Lambda @ Edge, pour permettre la publication, limiter le délai d'attente et permettre à Edgelambda.amazonaws.com invoquer la fonction | bool | false | Non |
lambda_at_edge_logs_all_regions | Que ce soit pour spécifier un joker dans la politique IAM utilisée par Lambda @ Edge pour permettre la connexion dans toutes les régions | bool | true | Non |
lambda_role | Je suis un rôle attaché à la fonction lambda. Cela régit à la fois qui / ce qui peut invoquer votre fonction lambda, ainsi que les ressources auxquelles notre fonction Lambda a accès. Voir le modèle d'autorisation Lambda pour plus de détails. | string | "" | Non |
calque_name | Nom de la couche Lambda pour créer | string | "" | Non |
couche_skip_destroy | S'il faut conserver l'ancienne version d'une couche Lambda précédemment déployée. | bool | false | Non |
couches | Liste de la version Lambda Couche ARNS (maximum de 5) pour se fixer à votre fonction lambda. | list(string) | null | Non |
Licence_info | Informations sur la licence pour votre couche Lambda. Par exemple, MIT ou URL complet d'une licence. | string | "" | Non |
local_existing_package | Le chemin absolu vers un fichier zip existant à utiliser | string | null | Non |
logging_application_log_level | Le niveau du journal d'application de la fonction lambda. Les valeurs valides sont "trace", "débogage", "info", "avertir", "erreur" ou "fatal". | string | "INFO" | Non |
logging_log_format | Le format de journal de la fonction lambda. Les valeurs valides sont "json" ou "texte". | string | "Text" | Non |
logging_log_group | Le groupe de journaux CloudWatch pour envoyer des journaux. | string | null | Non |
logging_system_log_level | Le niveau de journal système de la fonction lambda. Les valeurs valides sont "débogage", "info" ou "avertir". | string | "INFO" | Non |
maximum_event_age_in_seconds | Âge maximum d'une demande que Lambda envoie à une fonction de traitement en secondes. Valeurs valides entre 60 et 21600. | number | null | Non |
maximum_retry_attempts | Nombre maximum de fois pour réessayer lorsque la fonction renvoie une erreur. Valeurs valides entre 0 et 2. Par défaut, 2. | number | null | Non |
Memory_size | Quantité de mémoire dans MB Votre fonction Lambda peut utiliser au moment de l'exécution. Valeur valide entre 128 Mo et 10 240 Mo (10 Go), par incréments de 64 Mo. | number | 128 | Non |
numéro_of_policies | Nombre de politiques à attacher au rôle IAM pour la fonction lambda | number | 0 | Non |
numéro_of_policy_jsons | Nombre de politiques JSON à attacher au rôle IAM pour la fonction lambda | number | 0 | Non |
package_type | Le type de package de déploiement lambda. Options valides: fermeture éclair ou image | string | "Zip" | Non |
politiques | Liste des déclarations de politique ARN à attacher au rôle de fonction lambda | list(string) | [] | Non |
politique | Un document de politique supplémentaire ARN à attacher au rôle de fonction lambda | string | null | Non |
politique_json | Un document de politique supplémentaire en tant que JSON à attacher au rôle de fonction lambda | string | null | Non |
politique_jsons | Liste des documents de politique supplémentaires en tant que JSON à attacher au rôle de fonction lambda | list(string) | [] | Non |
Policy_name | IAM Nom de la politique. Il remplace la valeur par défaut, qui est la même que Role_name | string | null | Non |
politique_path | Le chemin des politiques à cela devrait être ajouté au rôle IAM pour la fonction lambda | string | null | Non |
Policy_statements | Carte des déclarations de stratégie dynamique à attacher au rôle de fonction lambda | any | {} | Non |
provisioned_concurrent_executions | Quantité de capacité à allouer. Réglé sur 1 ou plus pour activer, ou réglé sur 0 pour désactiver la concurrence provisionnée. | number | -1 | Non |
publier | Que ce soit pour publier la création / le changement en tant que nouvelle version de la fonction lambda. | bool | false | Non |
Poutine_khuylo | Êtes-vous d'accord que Poutine ne respecte pas la souveraineté ukrainienne et l'intégrité territoriale? Plus d'informations: https://en.wikipedia.org/wiki/Putin_khuylo! | bool | true | Non |
recréer_missing_package | Que ce soit pour recréer un package Lambda manquant s'il manque localement ou non | bool | true | Non |
Replace_security_groups_on_destroy | (Facultatif) Lorsqu'il est vrai, tous les groupes de sécurité définis dans VPC_SECURITY_GROUP_IDS seront remplacés par le groupe de sécurité par défaut une fois la fonction détruite. Définissez la variable remplacement_security_group_ids pour utiliser une liste personnalisée de groupes de sécurité pour le remplacement à la place. | bool | null | Non |
remplacement_security_group_ids | (Optional) List of security group IDs to assign to orphaned Lambda function network interfaces upon destruction. replace_security_groups_on_destroy must be set to true to use this attribute. | list(string) | null | Non |
reserved_concurrent_executions | The amount of reserved concurrent executions for this Lambda Function. A value of 0 disables Lambda Function from being triggered and -1 removes any concurrency limitations. Defaults to Unreserved Concurrency Limits -1. | number | -1 | Non |
role_description | Description of IAM role to use for Lambda Function | string | null | Non |
role_force_detach_policies | Specifies to force detaching any policies the IAM role has before destroying it. | bool | true | Non |
role_maximum_session_duration | Maximum session duration, in seconds, for the IAM role | number | 3600 | Non |
role_name | Name of IAM role to use for Lambda Function | string | null | Non |
role_path | Path of IAM role to use for Lambda Function | string | null | Non |
role_permissions_boundary | The ARN of the policy that is used to set the permissions boundary for the IAM role used by Lambda Function | string | null | Non |
role_tags | A map of tags to assign to IAM role | map(string) | {} | Non |
temps d'exécution | Lambda Function runtime | string | "" | Non |
s3_acl | The canned ACL to apply. Valid values are private, public-read, public-read-write, aws-exec-read, authenticated-read, bucket-owner-read, and bucket-owner-full-control. Defaults to private. | string | "private" | Non |
s3_bucket | S3 bucket to store artifacts | string | null | Non |
s3_existing_package | The S3 bucket object with keys bucket, key, version pointing to an existing zip-file to use | map(string) | null | Non |
s3_kms_key_id | Specifies a custom KMS key to use for S3 object encryption. | string | null | Non |
s3_object_override_default_tags | Whether to override the default_tags from provider? NB: S3 objects support a maximum of 10 tags. | bool | false | Non |
s3_object_storage_class | Specifies the desired Storage Class for the artifact uploaded to S3. Can be either STANDARD, REDUCED_REDUNDANCY, ONEZONE_IA, INTELLIGENT_TIERING, or STANDARD_IA. | string | "ONEZONE_IA" | Non |
s3_object_tags | A map of tags to assign to S3 bucket object. | map(string) | {} | Non |
s3_object_tags_only | Set to true to not merge tags with s3_object_tags. Useful to avoid breaching S3 Object 10 tag limit. | bool | false | Non |
s3_prefix | Directory name where artifacts should be stored in the S3 bucket. If unset, the path from artifacts_dir is used | string | null | Non |
s3_server_side_encryption | Specifies server-side encryption of the object in S3. Valid values are "AES256" and "aws:kms". | string | null | Non |
skip_destroy | Set to true if you do not wish the function to be deleted at destroy time, and instead just remove the function from the Terraform state. Useful for Lambda@Edge functions attached to CloudFront distributions. | bool | null | Non |
snap_start | (Optional) Snap start settings for low-latency startups | bool | false | Non |
source_path | The absolute path to a local file or directory containing your Lambda source code | any | null | Non |
store_on_s3 | Whether to store produced artifacts on S3 or locally. | bool | false | Non |
balises | A map of tags to assign to resources. | map(string) | {} | Non |
temps mort | The amount of time your Lambda Function has to run in seconds. | number | 3 | Non |
timeouts | Define maximum timeout for creating, updating, and deleting Lambda Function resources | map(string) | {} | Non |
tracing_mode | Tracing mode of the Lambda Function. Valid value can be either PassThrough or Active. | string | null | Non |
trigger_on_package_timestamp | Whether to recreate the Lambda package if the timestamp changes | bool | true | Non |
trusted_entities | List of additional trusted entities for assuming Lambda Function role (trust relationship) | any | [] | Non |
use_existing_cloudwatch_log_group | Whether to use an existing CloudWatch log group or create new | bool | false | Non |
vpc_security_group_ids | List of security group ids when Lambda Function should run in the VPC. | list(string) | null | Non |
vpc_subnet_ids | List of subnet ids when Lambda Function should run in the VPC. Usually private or intra subnets. | list(string) | null | Non |
Nom | Description |
---|---|
lambda_cloudwatch_log_group_arn | The ARN of the Cloudwatch Log Group |
lambda_cloudwatch_log_group_name | The name of the Cloudwatch Log Group |
lambda_event_source_mapping_arn | The event source mapping ARN |
lambda_event_source_mapping_function_arn | The the ARN of the Lambda function the event source mapping is sending events to |
lambda_event_source_mapping_state | The state of the event source mapping |
lambda_event_source_mapping_state_transition_reason | The reason the event source mapping is in its current state |
lambda_event_source_mapping_uuid | The UUID of the created event source mapping |
lambda_function_arn | The ARN of the Lambda Function |
lambda_function_arn_static | The static ARN of the Lambda Function. Use this to avoid cycle errors between resources (eg, Step Functions) |
lambda_function_invoke_arn | The Invoke ARN of the Lambda Function |
lambda_function_kms_key_arn | The ARN for the KMS encryption key of Lambda Function |
lambda_function_last_modified | The date Lambda Function resource was last modified |
lambda_function_name | The name of the Lambda Function |
lambda_function_qualified_arn | The ARN identifying your Lambda Function Version |
lambda_function_qualified_invoke_arn | The Invoke ARN identifying your Lambda Function Version |
lambda_function_signing_job_arn | ARN of the signing job |
lambda_function_signing_profile_version_arn | ARN of the signing profile version |
lambda_function_source_code_hash | Base64-encoded representation of raw SHA-256 sum of the zip file |
lambda_function_source_code_size | The size in bytes of the function .zip file |
lambda_function_url | The URL of the Lambda Function URL |
lambda_function_url_id | The Lambda Function URL generated id |
lambda_function_version | Latest published version of Lambda Function |
lambda_layer_arn | The ARN of the Lambda Layer with version |
lambda_layer_created_date | The date Lambda Layer resource was created |
lambda_layer_layer_arn | The ARN of the Lambda Layer without version |
lambda_layer_source_code_size | The size in bytes of the Lambda Layer .zip file |
lambda_layer_version | The Lambda Layer version |
lambda_role_arn | The ARN of the IAM role created for the Lambda Function |
lambda_role_name | The name of the IAM role created for the Lambda Function |
lambda_role_unique_id | The unique id of the IAM role created for the Lambda Function |
local_filename | The filename of zip archive deployed (if deployment was from local) |
s3_object | The map with S3 object data of zip archive deployed (if deployment was from S3) |
During development involving modifying python files, use tox to run unit tests:
tox
This will try to run unit tests which each supported python version, reporting errors for python versions which are not installed locally.
If you only want to test against your main python version:
tox -e py
You can also pass additional positional arguments to pytest which is used to run test, eg to make it verbose:
tox -e py -- -vvv
Module managed by Anton Babenko. Check out serverless.tf to learn more about doing serverless with Terraform.
Please reach out to Betajob if you are looking for commercial support for your Terraform, AWS, or serverless project.
Apache 2 Licensed. See LICENSE for full details.