diff --git a/LocalStack/Compute/LabLambda/README.md b/LocalStack/Compute/LabLambda/README.md new file mode 100644 index 0000000..46158e9 --- /dev/null +++ b/LocalStack/Compute/LabLambda/README.md @@ -0,0 +1,48 @@ + +# LambdaLayer + +Download python packages and create lambda layer + +## Notes +Packages need to be placed under a python/ subdirectory. +See https://docs.aws.amazon.com/lambda/latest/dg/packaging-layers.html + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 1.1.0 | +| aws | >= 6.0 | + +## Providers + +| Name | Version | +|------|---------| +| aws | 6.32.0 | +| random | 3.8.1 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| lambda\_archive | ../modules/compute/LambdaZipBuilder | n/a | +| s3 | terraform-aws-modules/s3-bucket/aws | 5.10.0 | + +## Resources + +| Name | Type | +|------|------| +| [aws_lambda_layer_version.pandas](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_layer_version) | resource | +| [random_uuid.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) | resource | + +## Inputs + +No inputs. + +## Outputs + +No outputs. + +--- +## Authorship +This module was developed by xpk. \ No newline at end of file diff --git a/LocalStack/Compute/LabLambda/helloworld.py b/LocalStack/Compute/LabLambda/helloworld.py new file mode 100644 index 0000000..522c3b4 --- /dev/null +++ b/LocalStack/Compute/LabLambda/helloworld.py @@ -0,0 +1,2 @@ +def lambda_handler(event, context): + return {"Result": "HelloWorld"} \ No newline at end of file diff --git a/LocalStack/Compute/LabLambda/lambda_layer.zip b/LocalStack/Compute/LabLambda/lambda_layer.zip new file mode 100644 index 0000000..953c5f1 Binary files /dev/null and b/LocalStack/Compute/LabLambda/lambda_layer.zip differ diff --git a/LocalStack/Compute/LabLambda/main.tf b/LocalStack/Compute/LabLambda/main.tf new file mode 100644 index 0000000..73da5c5 --- /dev/null +++ b/LocalStack/Compute/LabLambda/main.tf @@ -0,0 +1,68 @@ +/** +* # LabLambda +* +* Download python packages and create lambda layer +* Create lambda function and allow invocation from scheduler +* +* ## Notes +* Packages need to be placed under a python/ subdirectory. +* e.g. python/pandas in the zip file +* See https://docs.aws.amazon.com/lambda/latest/dg/packaging-layers.html + */ + +# build python package zip file +module "lambda_layer_archive" { + source = "../../../modules/compute/LambdaZipBuilder" + + pip_packages = "pandas numpy pytz openpyxl" + upload_archive_to_s3 = false + pip_path = "/my/work/xpk-git/venv314/bin/pip3" +} + +# create lambda layer +resource "aws_lambda_layer_version" "py_packages" { + description = "Python packages pandas numpy pytz openpyxl" + filename = module.lambda_layer_archive.archive_path + source_code_hash = module.lambda_layer_archive.archive_checksum + layer_name = "py_packages" + compatible_runtimes = ["python3.14"] +} + +resource "archive_file" "lambda_function_archive" { + source_file = "${path.module}/helloworld.py" + output_path = "/tmp/helloworld.zip" + type = "zip" +} + +resource "aws_lambda_function" "func1" { + function_name = "HelloWorldFunction" + runtime = "python3.14" + timeout = 5 + role = module.lambda_role.role-arn + filename = archive_file.lambda_function_archive.output_path + source_code_hash = archive_file.lambda_function_archive.output_sha256 + handler = "helloworld.lambda_handler" + layers = [aws_lambda_layer_version.py_packages.arn] + environment { + variables = { + foo = "bar" + } + } +} + +# Allow invocation by eventbridge scheduler +resource "aws_lambda_permission" "func1" { + statement_id = "AllowExecutionFromScheduler" + function_name = aws_lambda_function.func1.function_name + action = "lambda:InvokeFunction" + principal = "scheduler.amazonaws.com" +} + +module "lambda_role" { + source = "../../../modules/security_identity_compliance/iam-role-v2" + role-name = "LambdaFunctionRole" + description = "LambdaFunctionRole" + create-instance-profile = false + path = "/Lambda/" + trusted-entity = "lambda.amazonaws.com" +} \ No newline at end of file diff --git a/LocalStack/Compute/LabLambda/provider.tf b/LocalStack/Compute/LabLambda/provider.tf new file mode 100644 index 0000000..cde40b6 --- /dev/null +++ b/LocalStack/Compute/LabLambda/provider.tf @@ -0,0 +1,60 @@ +provider "aws" { + region = "us-east-1" + + # localstack config + access_key = "test" + secret_key = "test" + skip_credentials_validation = true + skip_metadata_api_check = true + skip_requesting_account_id = true + + # localstack endpoints https://docs.localstack.cloud/aws/integrations/infrastructure-as-code/terraform/#:~:text=tflocal%20is%20a%20small%20wrapper,unmodified%20Terraform%20scripts%20against%20LocalStack. + endpoints { + apigateway = "http://192.168.86.96:4566" + apigatewayv2 = "http://192.168.86.96:4566" + cloudformation = "http://192.168.86.96:4566" + cloudwatch = "http://192.168.86.96:4566" + dynamodb = "http://192.168.86.96:4566" + ec2 = "http://192.168.86.96:4566" + es = "http://192.168.86.96:4566" + elasticache = "http://192.168.86.96:4566" + firehose = "http://192.168.86.96:4566" + iam = "http://192.168.86.96:4566" + kinesis = "http://192.168.86.96:4566" + kms = "http://192.168.86.96:4566" + lambda = "http://192.168.86.96:4566" + rds = "http://192.168.86.96:4566" + redshift = "http://192.168.86.96:4566" + route53 = "http://192.168.86.96:4566" + s3 = "http://192.168.86.96:4566" + secretsmanager = "http://192.168.86.96:4566" + ses = "http://192.168.86.96:4566" + sns = "http://192.168.86.96:4566" + sqs = "http://192.168.86.96:4566" + ssm = "http://192.168.86.96:4566" + stepfunctions = "http://192.168.86.96:4566" + sts = "http://192.168.86.96:4566" + } + + default_tags { + tags = { + Environment = "LocalStack" + TerraformDir = join("/", reverse(slice(reverse(split("/", path.cwd)), 0, 2))) + LocalStack = true + } + } +} + +terraform { + required_version = ">= 1.11.0" + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 6.0" + } + archive = { + source = "hashicorp/archive" + version = "2.7.1" + } + } +} \ No newline at end of file diff --git a/LocalStack/README.md b/LocalStack/README.md index f38d337..c8cfa23 100644 --- a/LocalStack/README.md +++ b/LocalStack/README.md @@ -1,4 +1,7 @@ # LocalStack +It's a fair tool to test terraform code without actually deploying anything on aws. +However, there are a few limitations on LocalStack. + ## Setup Sign up for localstack and obtain the auth token. Then fire up a container: @@ -13,8 +16,7 @@ docker run \ -e AWS_ACCESS_KEY_ID=test \ -e AWS_SECRET_ACCESS_KEY=test \ -e SERVICES="s3,iam,lambda,dynamodb,cloudwatch,rds,ec2,secretsmanager" \ --e DEBUG=1 \ --v /run/containerd/containerd.sock:/var/run/docker.sock \ +-e DEBUG=0 \ -d --rm --name localstack --network macvlan localstack/localstack localstack ``` @@ -73,9 +75,18 @@ For example, vpc with ipv6 could not be created. It failed with the following er ``` -Also, ec2 instance's associate_public_ip_address attribute is always set to true, despite +Also, ec2 instance's ```associate_public_ip_address``` attribute is always set to true, despite it is set to false in my code. This caused the instance to be redeployed everytime terraform apply is ran. +If I tried to deploy a lambda function, LocalStack actually tried to create an executable container +via docker. That cannot be disabled and without docker, I got this error when trying to deploy a function. +Subsequently, I cannot destroy the function since provisioning failed. + +```text +Error: waiting for Lambda Function (HelloWorldFunction) create: unexpected state 'Failed', wanted target +'Active, ActiveNonInvocable'. last error: InternalError: Error while creating lambda: Docker not available +``` + Both the free and community editions of LocalStack do not support rds, among other services described in https://docs.localstack.cloud/aws/licensing/ \ No newline at end of file