From 06967a48dd1048acad39238e628f3749a5b05853 Mon Sep 17 00:00:00 2001 From: Bala Bala Date: Thu, 4 Jan 2024 21:02:01 -0500 Subject: [PATCH 01/13] bb245-feature-alb-lambda-path-based-routing-sam-py --- alb-lambda-rest-api-sam-py/Pipfile | 13 ++ alb-lambda-rest-api-sam-py/README.md | 147 ++++++++++++++++++ .../docs/alb_lambda_api_sam_py.png | Bin 0 -> 17897 bytes alb-lambda-rest-api-sam-py/events/event.json | 61 ++++++++ .../example-pattern.json | 72 +++++++++ alb-lambda-rest-api-sam-py/src/app.py | 28 ++++ alb-lambda-rest-api-sam-py/template.yaml | 146 +++++++++++++++++ 7 files changed, 467 insertions(+) create mode 100644 alb-lambda-rest-api-sam-py/Pipfile create mode 100644 alb-lambda-rest-api-sam-py/README.md create mode 100644 alb-lambda-rest-api-sam-py/docs/alb_lambda_api_sam_py.png create mode 100644 alb-lambda-rest-api-sam-py/events/event.json create mode 100644 alb-lambda-rest-api-sam-py/example-pattern.json create mode 100644 alb-lambda-rest-api-sam-py/src/app.py create mode 100644 alb-lambda-rest-api-sam-py/template.yaml diff --git a/alb-lambda-rest-api-sam-py/Pipfile b/alb-lambda-rest-api-sam-py/Pipfile new file mode 100644 index 000000000..6d68c0ac0 --- /dev/null +++ b/alb-lambda-rest-api-sam-py/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +aws-lambda-powertools = {version = "*"} + +[dev-packages] +aws-lambda-powertools = {extra = ["all"], version = "*"} + +[requires] +python_version = "3.9" \ No newline at end of file diff --git a/alb-lambda-rest-api-sam-py/README.md b/alb-lambda-rest-api-sam-py/README.md new file mode 100644 index 000000000..ddcf756f0 --- /dev/null +++ b/alb-lambda-rest-api-sam-py/README.md @@ -0,0 +1,147 @@ +# AWS Lambda RESTful API with Amazon ALB and Path Based Listener Rules + +This configuration employs Python 3.9 and the Serverless Application Model (SAM) CLI to establish an Application Load +Balancer with path-based listener rules, paired with an AWS Lambda RESTful API function as the target. + +Learn more about this pattern +at [Serverless Land Patterns](https://serverlessland.com/patterns/alb-lambda-rest-api-sam-py). + +Important: this application uses various AWS services and there are costs associated with these services after the Free +Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any +AWS costs incurred. No warranty is implied in this example. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already + have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls + and manage AWS resources. +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) ( + AWS SAM) installed +* [Python 3 installed](https://www.python.org/downloads/) +* [Docker](https://www.docker.com/products/docker-desktop/) + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` +2. Change directory to the pattern directory: + ``` + cd alb-lambda-rest-api-sam-py + ``` +3. Install dependencies and build: + ``` + pipenv install + ``` +4. From the command line, use AWS SAM to deploy the AWS resources for the pattern as specified in the template.yml file: + ``` + sam validate && sam build && sam deploy --guided + ``` +5. During the prompts: + * Enter a stack name + * Enter the desired AWS Region + * Allow SAM CLI to create IAM roles with the required permissions. + +6. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for + testing. + +## How it works + +This setup orchestrates the deployment of an Application Load Balancer, configures path-based routes directing traffic +to a Python-based AWS Lambda function, and leverages +the [AWS Lambda Powertools for Python](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/) +library. The Lambda function, serving as the target, records details of the incoming ALB event, along with the API and +context objects, logging them to an Amazon CloudWatch Logs log group and Amazon X-Ray. + +## Testing + +### SAM CLI for Local API Testing + +The SAM CLI seamlessly extends the capabilities of the AWS CLI, introducing essential features for constructing and validating Lambda applications. Leveraging the power of Docker, it orchestrates the execution of functions within an Amazon Linux environment aligned with the Lambda runtime specifications, all sourced from [sam/build-python3.9](https://gallery.ecr.aws/sam/build-python3.9). +This emulation replicates the Lambda environment. + +To simulate an ALB (Application Load Balancer) event, the CLI relies on the configuration stored in [event.json](./events/event.json). This file corresponds to an ALB event, and it is generated by the SAM command: `sam local generate-event alb request`. + +Now, to build and execute your function, execute the following command: + + +```commandline +pipenv requirements > requirements.txt +sam build +sam local invoke -e events/event.json +``` + +### Deploy and Test API in AWS + +Once the application is deployed, retrieve the Application Load Balancer endpoint value from CloudFormation Outputs. + +```commandline +curl --request GET --header "Client-Correlation-Id:bb245" --url http://{ALB_ID}.{REGION}.elb.amazonaws.com/hello' +``` + +Alternatively, you can use [xh utility](https://github.com/ducaale/xh), too as: + +```commandline +xh http://{ALB_ID}.{REGION}.elb.amazonaws.com/hello Client-Correlation-Id:bb245 +``` + +Response: + +```commandline +HTTP/1.1 200 OK +Connection: keep-alive +Content-Length: 37 +Content-Type: application/json +Server: awselb/2.0 + +{ + "message": "Hi from API behind ALB" +} + +``` + +When an invalid resource (/nf-test) is used as: + +```commandline +curl --request GET --header "Client-Correlation-Id:not-found-test-1" --url http://{ALB_ID}.{REGION}.elb.amazonaws.com/nf-test' +``` +_OR_ + +with [xh utility](https://github.com/ducaale/xh) as: + +```commandline +xh http://{ALB_ID}.{REGION}.elb.amazonaws.com/nf-test Client-Correlation-Id:'not-found-test-1' +``` + +Response: + +```commandline +HTTP/1.1 400 Bad Request +Connection: keep-alive +Content-Length: 27 +Content-Type: text/plain; charset=utf-8 +Date: Wed, 27 Dec 2023 23:13:43 GMT +Server: awselb/2.0 + +404 Error!!! Page Not Found + +``` + +## Cleanup + +1. Delete the stack + ```bash + sam delete + ``` +2. Confirm the stack has been deleted + ```bash + aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus" + ``` + +---- +Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 \ No newline at end of file diff --git a/alb-lambda-rest-api-sam-py/docs/alb_lambda_api_sam_py.png b/alb-lambda-rest-api-sam-py/docs/alb_lambda_api_sam_py.png new file mode 100644 index 0000000000000000000000000000000000000000..be2c0f82f2c43668902ed5d84ea9390e14ccc32f GIT binary patch literal 17897 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 literal 0 HcmV?d00001 diff --git a/alb-lambda-rest-api-sam-py/events/event.json b/alb-lambda-rest-api-sam-py/events/event.json new file mode 100644 index 000000000..7fe6f0bd2 --- /dev/null +++ b/alb-lambda-rest-api-sam-py/events/event.json @@ -0,0 +1,61 @@ +{ + "body": "null", + "resource": "/{proxy+}", + "path": "/hello", + "httpMethod": "GET", + "isBase64Encoded": true, + "queryStringParameters": null, + "pathParameters": { + "proxy": "/hello" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "application/json;v=1", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https", + "Client-Correlation-Id": "bb245" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "hello", + "resourcePath": "/{proxy+}", + "httpMethod": "GET", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} \ No newline at end of file diff --git a/alb-lambda-rest-api-sam-py/example-pattern.json b/alb-lambda-rest-api-sam-py/example-pattern.json new file mode 100644 index 000000000..d54b6d41d --- /dev/null +++ b/alb-lambda-rest-api-sam-py/example-pattern.json @@ -0,0 +1,72 @@ +{ + "title": "AWS Lambda REST API and Amazon ALB with Listener Rules", + "description": "This configuration employs Python 3.9 and the Serverless Application Model (SAM) CLI to establish an Application Load Balancer with route-based listener rules, paired with an AWS Lambda RESTful API function as the target.", + "language": "Python", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This setup orchestrates the deployment of an Application Load Balancer, configures path-based routes directing traffic to a Python-based AWS Lambda function, and leverages the [AWS Lambda Powertools for Python](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/) library. The Lambda function, serving as the target, records details of the incoming ALB event, along with the API and context objects, logging them to an Amazon CloudWatch Logs log group and Amazon X-Ray." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/alb-lambda-rest-api-sam-py", + "templateURL": "serverless-patterns/alb-lambda-rest-api-sam-py", + "projectFolder": "alb-lambda-rest-api-sam-py", + "templateFile": "template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "AWS CLI", + "link": "https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html" + }, + { + "text": "SAM CLI", + "Link": "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html" + }, + { + "text": "Python 3", + "Link": "https://www.python.org/downloads/" + }, + { + "text": "AWS SAM build image for Python 3.9", + "Link": "https://gallery.ecr.aws/sam/build-python3.9" + }, + { + "text": "Docker Desktop", + "Link": "https://www.docker.com/products/docker-desktop/" + }, + { + "text": "Using AWS Lambda with an Application Load Balancer", + "Link": "https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html" + } + ] + }, + "deploy": { + "text": [ + "sam validate && sam build && sam deploy --guided" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: sam delete." + ] + }, + "authors": [ + { + "name": "Balasubrahmanya Balakrishna", + "image": "https://github.com/bb245/balabala/blob/main/balabala.png", + "bio": "Balasubrahmanya Balakrishna is a Senior Lead Software Engineer with Capital One Services, LLC.", + "linkedin": "bala~bala" + } + ] +} \ No newline at end of file diff --git a/alb-lambda-rest-api-sam-py/src/app.py b/alb-lambda-rest-api-sam-py/src/app.py new file mode 100644 index 000000000..5a5fb390d --- /dev/null +++ b/alb-lambda-rest-api-sam-py/src/app.py @@ -0,0 +1,28 @@ +import json +from http import HTTPStatus + +from aws_lambda_powertools import Logger +from aws_lambda_powertools.event_handler import ALBResolver, Response, content_types +from aws_lambda_powertools.utilities.typing import LambdaContext +from aws_lambda_powertools.logging import correlation_paths + +log = Logger() +app = ALBResolver() + + +@app.get("/hello") +def sample_get() -> Response: + client_correlation_id = app.current_event.get_header_value(name="Client-Correlation-Id") + log.info(f"client_correlation_id: {client_correlation_id}") + response = { + "message": "Hi from API behind ALB" + } + return Response(status_code=int(HTTPStatus.OK), body=json.dumps(response), + content_type=content_types.APPLICATION_JSON) + + +@log.inject_lambda_context(correlation_id_path=correlation_paths.APPLICATION_LOAD_BALANCER, log_event=True, + clear_state=True) +def lambda_handler(event: dict, context: LambdaContext) -> dict: + log.debug(event) + return app.resolve(event, context) \ No newline at end of file diff --git a/alb-lambda-rest-api-sam-py/template.yaml b/alb-lambda-rest-api-sam-py/template.yaml new file mode 100644 index 000000000..1c9ef625f --- /dev/null +++ b/alb-lambda-rest-api-sam-py/template.yaml @@ -0,0 +1,146 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + alb-lambda-rest-api-sam-py + + SAM Template for ALB -> Lambda with Python Runtime +Parameters: + VPCId: + Type: String +# VPC ID - AWS::EC2::VPC::Id + Default: + Subnets: + Type: String +# comma separated subnet ids (AWS::EC2::Subnet::Id) + Default: + AppName: + Type: String + Default: alb-lambda-rest-api-sam-py + AlbLambdaRestApiSamPyFunctionRulePath: + Type: String + Default: /hello + AlbLambdaRestApiSamPyFunctionPriority: + Type: Number + Default: 10 +Globals: + Function: + Timeout: 3 + MemorySize: 128 + Tracing: Active + Environment: + Variables: + POWERTOOLS_SERVICE_NAME: alb-lambda-rest-api-sam-py + LOG_LEVEL: DEBUG + Api: + TracingEnabled: true +Resources: + AlbLambdaRestApiSamPyFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: . + Handler: src.app.lambda_handler + Runtime: python3.9 + Architectures: + - x86_64 + Policies: + - AWSLambdaBasicExecutionRole + + AlbLambdaRestApiSamPyFunctionPermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !GetAtt AlbLambdaRestApiSamPyFunction.Arn + Action: lambda:InvokeFunction + Principal: elasticloadbalancing.amazonaws.com + + AlbLambdaRestApiSamPyFunctionLoadBalancer: + Type: AWS::ElasticLoadBalancingV2::LoadBalancer + Properties: + Type: application + Scheme: internet-facing + Subnets: + Fn::Split: + - "," + - !Ref Subnets + SecurityGroups: [ !Ref AlbLambdaRestApiSamPyFunctionSecurityGroup ] + Tags: + - Key: name + Value: !Ref AWS::StackName + + AlbLambdaRestApiSamPyFunctionTargetGroup: + Type: AWS::ElasticLoadBalancingV2::TargetGroup + DependsOn: AlbLambdaRestApiSamPyFunctionPermission + Properties: + Name: !Sub ${AppName}-tg + HealthCheckEnabled: false + TargetType: lambda + Targets: + - Id: !GetAtt AlbLambdaRestApiSamPyFunction.Arn + Tags: + - Key: name + Value: !Ref AWS::StackName + + HttpListener: + Type: AWS::ElasticLoadBalancingV2::Listener + Properties: + DefaultActions: + - Type: fixed-response + FixedResponseConfig: + ContentType: text/plain + MessageBody: 404 Error!!! Page Not Found + StatusCode: 400 + LoadBalancerArn: !Ref AlbLambdaRestApiSamPyFunctionLoadBalancer + Port: 80 + Protocol: HTTP + + AlbLambdaRestApiSamPyFunctionHttpListenerRule: + Type: AWS::ElasticLoadBalancingV2::ListenerRule + Properties: + Actions: + - TargetGroupArn: !Ref AlbLambdaRestApiSamPyFunctionTargetGroup + Type: forward + Conditions: + - Field: path-pattern + Values: + - !Ref AlbLambdaRestApiSamPyFunctionRulePath + ListenerArn: !Ref HttpListener + Priority: !Ref AlbLambdaRestApiSamPyFunctionPriority + + AlbLambdaRestApiSamPyFunctionSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupName: !Ref AWS::StackName + GroupDescription: Allow http on port 80 + VpcId: !Ref VPCId + SecurityGroupIngress: + - IpProtocol: tcp + FromPort: 80 + ToPort: 80 + CidrIp: 0.0.0.0/0 + Tags: + - Key: name + Value: !Ref AWS::StackName + + ApplicationResourceGroup: + Type: AWS::ResourceGroups::Group + Properties: + Name: + Fn::Sub: ApplicationInsights-SAM-${AWS::StackName} + ResourceQuery: + Type: CLOUDFORMATION_STACK_1_0 + + ApplicationInsightsMonitoring: + Type: AWS::ApplicationInsights::Application + Properties: + ResourceGroupName: + Ref: ApplicationResourceGroup + AutoConfigurationEnabled: 'true' + +Outputs: + AlbLambdaRestApiSamPyFunction: + Description: ALB Lambda SAM Python Sample Lambda Function ARN + Value: !GetAtt AlbLambdaRestApiSamPyFunction.Arn + AlbLambdaRestApiSamPyFunctionIamRole: + Description: Implicit IAM Role created for ALB Lambda SAM Python Sample Lambda function + Value: !GetAtt AlbLambdaRestApiSamPyFunctionRole.Arn + DNSName: + Value: !GetAtt AlbLambdaRestApiSamPyFunctionLoadBalancer.DNSName \ No newline at end of file From 2dd727301c0f4290f5f5a5f223882dff44876c17 Mon Sep 17 00:00:00 2001 From: Bala Bala Date: Tue, 9 Jan 2024 16:26:58 -0500 Subject: [PATCH 02/13] Apply gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7bde3b6d2..4ea8fc30b 100644 --- a/.gitignore +++ b/.gitignore @@ -234,4 +234,5 @@ terraform.rc #Ignore Intellij files *.iml -*.idea \ No newline at end of file +*.idea +.torchignore \ No newline at end of file From 54d03eb9569f8564359dc165120f77368d9b6931 Mon Sep 17 00:00:00 2001 From: Bala Bala Date: Wed, 10 Jan 2024 11:51:56 -0500 Subject: [PATCH 03/13] Clean up and address review comments --- alb-lambda-rest-api-sam-py/README.md | 11 ++++++++--- alb-lambda-rest-api-sam-py/example-pattern.json | 6 +++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/alb-lambda-rest-api-sam-py/README.md b/alb-lambda-rest-api-sam-py/README.md index ddcf756f0..295ab6fa7 100644 --- a/alb-lambda-rest-api-sam-py/README.md +++ b/alb-lambda-rest-api-sam-py/README.md @@ -1,7 +1,7 @@ # AWS Lambda RESTful API with Amazon ALB and Path Based Listener Rules -This configuration employs Python 3.9 and the Serverless Application Model (SAM) CLI to establish an Application Load -Balancer with path-based listener rules, paired with an AWS Lambda RESTful API function as the target. +This configuration pattern creates an Application Load +Balancer with path-based listener rules, paired with an AWS Lambda RESTful API function as the target. It uses Python 3.9 and the Serverless Application Model (SAM) CLI. Learn more about this pattern at [Serverless Land Patterns](https://serverlessland.com/patterns/alb-lambda-rest-api-sam-py). @@ -20,6 +20,7 @@ AWS costs incurred. No warranty is implied in this example. * [AWS Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) ( AWS SAM) installed * [Python 3 installed](https://www.python.org/downloads/) +* [AWS Lambda Powertools for Python](https://docs.powertools.aws.dev/lambda/python/latest/) * [Docker](https://www.docker.com/products/docker-desktop/) ## Deployment Instructions @@ -43,6 +44,8 @@ AWS costs incurred. No warranty is implied in this example. 5. During the prompts: * Enter a stack name * Enter the desired AWS Region + * Enter VPC ID + * Enter comma seperated Subnet IDs for e.g, subnet-1,subnet-2 * Allow SAM CLI to create IAM roles with the required permissions. 6. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for @@ -52,10 +55,12 @@ AWS costs incurred. No warranty is implied in this example. This setup orchestrates the deployment of an Application Load Balancer, configures path-based routes directing traffic to a Python-based AWS Lambda function, and leverages -the [AWS Lambda Powertools for Python](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/) +the [AWS Lambda Powertools for Python](https://docs.powertools.aws.dev/lambda/python/latest/core/event_handler/api_gateway/#application-load-balancer) library. The Lambda function, serving as the target, records details of the incoming ALB event, along with the API and context objects, logging them to an Amazon CloudWatch Logs log group and Amazon X-Ray. +Note: ALB has no authentication or authorization and should only be used for demo purposes. + ## Testing ### SAM CLI for Local API Testing diff --git a/alb-lambda-rest-api-sam-py/example-pattern.json b/alb-lambda-rest-api-sam-py/example-pattern.json index d54b6d41d..3f0226d50 100644 --- a/alb-lambda-rest-api-sam-py/example-pattern.json +++ b/alb-lambda-rest-api-sam-py/example-pattern.json @@ -1,6 +1,6 @@ { "title": "AWS Lambda REST API and Amazon ALB with Listener Rules", - "description": "This configuration employs Python 3.9 and the Serverless Application Model (SAM) CLI to establish an Application Load Balancer with route-based listener rules, paired with an AWS Lambda RESTful API function as the target.", + "description": "This pattern creates an Application Load Balancer with route-based listener rules, paired with an AWS Lambda RESTful API function as the target. It uses Python 3.9 and the Serverless Application Model (SAM) CLI.", "language": "Python", "level": "200", "framework": "SAM", @@ -43,6 +43,10 @@ { "text": "Using AWS Lambda with an Application Load Balancer", "Link": "https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html" + }, + { + "text": "Powertools for AWS Lambda (Python)", + "Link": "https://docs.powertools.aws.dev/lambda/python/latest/" } ] }, From aa376861097b9670bf4e8be70e69388f8aa743dc Mon Sep 17 00:00:00 2001 From: Bala Bala Date: Wed, 10 Jan 2024 16:15:10 -0500 Subject: [PATCH 04/13] Revert .gitignore --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4ea8fc30b..7bde3b6d2 100644 --- a/.gitignore +++ b/.gitignore @@ -234,5 +234,4 @@ terraform.rc #Ignore Intellij files *.iml -*.idea -.torchignore \ No newline at end of file +*.idea \ No newline at end of file From edf18b0b9936e848c16054da61ced12af7ad508e Mon Sep 17 00:00:00 2001 From: Balasubrahmanya Balakrishna Date: Wed, 10 Jan 2024 16:49:34 -0500 Subject: [PATCH 05/13] Add pipenv install to the command list --- alb-lambda-rest-api-sam-py/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/alb-lambda-rest-api-sam-py/README.md b/alb-lambda-rest-api-sam-py/README.md index 295ab6fa7..5ae82650b 100644 --- a/alb-lambda-rest-api-sam-py/README.md +++ b/alb-lambda-rest-api-sam-py/README.md @@ -74,7 +74,9 @@ Now, to build and execute your function, execute the following command: ```commandline +pipenv install pipenv requirements > requirements.txt + sam build sam local invoke -e events/event.json ``` @@ -149,4 +151,4 @@ Server: awselb/2.0 ---- Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. -SPDX-License-Identifier: MIT-0 \ No newline at end of file +SPDX-License-Identifier: MIT-0 From e1d78b344ad797602c251b3c1d4a225a4c2c31c1 Mon Sep 17 00:00:00 2001 From: Balasubrahmanya Balakrishna Date: Thu, 11 Jan 2024 09:40:52 -0500 Subject: [PATCH 06/13] Update Deployment instructions --- alb-lambda-rest-api-sam-py/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/alb-lambda-rest-api-sam-py/README.md b/alb-lambda-rest-api-sam-py/README.md index 5ae82650b..d57db3fde 100644 --- a/alb-lambda-rest-api-sam-py/README.md +++ b/alb-lambda-rest-api-sam-py/README.md @@ -33,11 +33,12 @@ AWS costs incurred. No warranty is implied in this example. ``` cd alb-lambda-rest-api-sam-py ``` -3. Install dependencies and build: +3. Install dependencies: ``` pipenv install + pipenv requirements > requirements.txt ``` -4. From the command line, use AWS SAM to deploy the AWS resources for the pattern as specified in the template.yml file: +4. From the command line, use AWS SAM to validate, build and deploy the AWS resources for the pattern as specified in the template.yml file: ``` sam validate && sam build && sam deploy --guided ``` From aad90cf60c4267bfe7a5915a7e18fbb7b3db7aef Mon Sep 17 00:00:00 2001 From: Balasubrahmanya Balakrishna Date: Thu, 11 Jan 2024 09:43:43 -0500 Subject: [PATCH 07/13] Update description in example-pattern.json --- alb-lambda-rest-api-sam-py/example-pattern.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alb-lambda-rest-api-sam-py/example-pattern.json b/alb-lambda-rest-api-sam-py/example-pattern.json index 3f0226d50..7a6ad2b39 100644 --- a/alb-lambda-rest-api-sam-py/example-pattern.json +++ b/alb-lambda-rest-api-sam-py/example-pattern.json @@ -1,6 +1,6 @@ { "title": "AWS Lambda REST API and Amazon ALB with Listener Rules", - "description": "This pattern creates an Application Load Balancer with route-based listener rules, paired with an AWS Lambda RESTful API function as the target. It uses Python 3.9 and the Serverless Application Model (SAM) CLI.", + "description": "This pattern creates an Application Load Balancer with route-based listener rules, paired with an AWS Lambda function as the target.", "language": "Python", "level": "200", "framework": "SAM", @@ -73,4 +73,4 @@ "linkedin": "bala~bala" } ] -} \ No newline at end of file +} From 67d57d03ff47e919c402778c252ce1e5a3815dec Mon Sep 17 00:00:00 2001 From: Balasubrahmanya Balakrishna Date: Thu, 11 Jan 2024 13:42:28 -0500 Subject: [PATCH 08/13] Update copyright year string to 2024 --- alb-lambda-rest-api-sam-py/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/alb-lambda-rest-api-sam-py/README.md b/alb-lambda-rest-api-sam-py/README.md index d57db3fde..352d6f92a 100644 --- a/alb-lambda-rest-api-sam-py/README.md +++ b/alb-lambda-rest-api-sam-py/README.md @@ -141,15 +141,15 @@ Server: awselb/2.0 ## Cleanup 1. Delete the stack - ```bash + ```commandline sam delete ``` 2. Confirm the stack has been deleted - ```bash + ```commandline aws cloudformation list-stacks --query "StackSummaries[?contains(StackName,'STACK_NAME')].StackStatus" ``` ---- -Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 From 4b16e205c510a6c56f2c8203e2d48989d085ec7b Mon Sep 17 00:00:00 2001 From: Balasubrahmanya Balakrishna Date: Fri, 12 Jan 2024 13:52:03 -0500 Subject: [PATCH 09/13] Clean up and add Pipfile.lock and requirements.txt for ease --- alb-lambda-rest-api-sam-py/Pipfile.lock | 54 +++++++++++++++++++ alb-lambda-rest-api-sam-py/README.md | 4 +- .../example-pattern.json | 2 +- alb-lambda-rest-api-sam-py/requirements.txt | 3 ++ alb-lambda-rest-api-sam-py/template.yaml | 16 +++--- 5 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 alb-lambda-rest-api-sam-py/Pipfile.lock create mode 100644 alb-lambda-rest-api-sam-py/requirements.txt diff --git a/alb-lambda-rest-api-sam-py/Pipfile.lock b/alb-lambda-rest-api-sam-py/Pipfile.lock new file mode 100644 index 000000000..77497b110 --- /dev/null +++ b/alb-lambda-rest-api-sam-py/Pipfile.lock @@ -0,0 +1,54 @@ +{ + "_meta": { + "hash": { + "sha256": "95a86ddb5eb2be624c7a545ce418fa3780adfb09d35348ac4c436ffac1573263" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.9" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "aws-lambda-powertools": { + "hashes": [ + "sha256:082762c0939caa670d69b8988142710029bfac050dbd428af0d12570b8a6c7be", + "sha256:d628e32919379fde4cd238578bc47fcc60a43f742bd8daa68533bc5202eae378" + ], + "markers": "python_full_version >= '3.7.4' and python_full_version < '4.0.0'", + "version": "==2.31.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", + "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + ], + "markers": "python_version >= '3.8'", + "version": "==4.9.0" + } + }, + "develop": { + "aws-lambda-powertools": { + "hashes": [ + "sha256:082762c0939caa670d69b8988142710029bfac050dbd428af0d12570b8a6c7be", + "sha256:d628e32919379fde4cd238578bc47fcc60a43f742bd8daa68533bc5202eae378" + ], + "markers": "python_full_version >= '3.7.4' and python_full_version < '4.0.0'", + "version": "==2.31.0" + }, + "typing-extensions": { + "hashes": [ + "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783", + "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd" + ], + "markers": "python_version >= '3.8'", + "version": "==4.9.0" + } + } +} diff --git a/alb-lambda-rest-api-sam-py/README.md b/alb-lambda-rest-api-sam-py/README.md index 352d6f92a..03fd47b1e 100644 --- a/alb-lambda-rest-api-sam-py/README.md +++ b/alb-lambda-rest-api-sam-py/README.md @@ -127,11 +127,11 @@ xh http://{ALB_ID}.{REGION}.elb.amazonaws.com/nf-test Client-Correlation-Id:'not Response: ```commandline -HTTP/1.1 400 Bad Request +HTTP/1.1 404 Not Found Connection: keep-alive Content-Length: 27 Content-Type: text/plain; charset=utf-8 -Date: Wed, 27 Dec 2023 23:13:43 GMT +Date: Fri, 12 Jan 2024 18:44:09 GMT Server: awselb/2.0 404 Error!!! Page Not Found diff --git a/alb-lambda-rest-api-sam-py/example-pattern.json b/alb-lambda-rest-api-sam-py/example-pattern.json index 7a6ad2b39..6b4dd4206 100644 --- a/alb-lambda-rest-api-sam-py/example-pattern.json +++ b/alb-lambda-rest-api-sam-py/example-pattern.json @@ -69,7 +69,7 @@ { "name": "Balasubrahmanya Balakrishna", "image": "https://github.com/bb245/balabala/blob/main/balabala.png", - "bio": "Balasubrahmanya Balakrishna is a Senior Lead Software Engineer with Capital One Services, LLC.", + "bio": "Senior Lead Software Engineer, Capital One Services, LLC.", "linkedin": "bala~bala" } ] diff --git a/alb-lambda-rest-api-sam-py/requirements.txt b/alb-lambda-rest-api-sam-py/requirements.txt new file mode 100644 index 000000000..0aa6fe00f --- /dev/null +++ b/alb-lambda-rest-api-sam-py/requirements.txt @@ -0,0 +1,3 @@ +-i https://pypi.org/simple +aws-lambda-powertools==2.31.0; python_full_version >= '3.7.4' and python_full_version < '4.0.0' +typing-extensions==4.9.0; python_version >= '3.8' diff --git a/alb-lambda-rest-api-sam-py/template.yaml b/alb-lambda-rest-api-sam-py/template.yaml index 1c9ef625f..49c004c04 100644 --- a/alb-lambda-rest-api-sam-py/template.yaml +++ b/alb-lambda-rest-api-sam-py/template.yaml @@ -1,18 +1,15 @@ AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 -Description: > - alb-lambda-rest-api-sam-py - - SAM Template for ALB -> Lambda with Python Runtime +Description: AWS Lambda REST API and Amazon ALB with Listener Rules Parameters: VPCId: Type: String -# VPC ID - AWS::EC2::VPC::Id - Default: +# TODO: Substitute VPC ID - AWS::EC2::VPC::Id + Default: VPC_ID Subnets: Type: String -# comma separated subnet ids (AWS::EC2::Subnet::Id) - Default: +# TODO: Substitute comma separated subnet IDs (AWS::EC2::Subnet::Id) + Default: subnet-1,subnet-2,subnet-3 AppName: Type: String Default: alb-lambda-rest-api-sam-py @@ -55,6 +52,7 @@ Resources: AlbLambdaRestApiSamPyFunctionLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: + Name: !Sub ${AppName}-alb Type: application Scheme: internet-facing Subnets: @@ -87,7 +85,7 @@ Resources: FixedResponseConfig: ContentType: text/plain MessageBody: 404 Error!!! Page Not Found - StatusCode: 400 + StatusCode: 404 LoadBalancerArn: !Ref AlbLambdaRestApiSamPyFunctionLoadBalancer Port: 80 Protocol: HTTP From 37a99c86a7f5a3500457fb2192d5ae38d354b6c1 Mon Sep 17 00:00:00 2001 From: Bala Bala Date: Fri, 12 Jan 2024 14:31:37 -0500 Subject: [PATCH 10/13] Remove comments from template.yaml --- alb-lambda-rest-api-sam-py/template.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/alb-lambda-rest-api-sam-py/template.yaml b/alb-lambda-rest-api-sam-py/template.yaml index 49c004c04..229b6760c 100644 --- a/alb-lambda-rest-api-sam-py/template.yaml +++ b/alb-lambda-rest-api-sam-py/template.yaml @@ -4,11 +4,9 @@ Description: AWS Lambda REST API and Amazon ALB with Listener Rules Parameters: VPCId: Type: String -# TODO: Substitute VPC ID - AWS::EC2::VPC::Id Default: VPC_ID Subnets: Type: String -# TODO: Substitute comma separated subnet IDs (AWS::EC2::Subnet::Id) Default: subnet-1,subnet-2,subnet-3 AppName: Type: String From 9d892a79281a58adef576739c1e707a416162aa7 Mon Sep 17 00:00:00 2001 From: Bala Bala Date: Fri, 12 Jan 2024 14:48:49 -0500 Subject: [PATCH 11/13] Add SecurityGroupEgress tp address liniting --- alb-lambda-rest-api-sam-py/template.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/alb-lambda-rest-api-sam-py/template.yaml b/alb-lambda-rest-api-sam-py/template.yaml index 229b6760c..62048efc3 100644 --- a/alb-lambda-rest-api-sam-py/template.yaml +++ b/alb-lambda-rest-api-sam-py/template.yaml @@ -107,6 +107,9 @@ Resources: GroupName: !Ref AWS::StackName GroupDescription: Allow http on port 80 VpcId: !Ref VPCId + SecurityGroupEgress: + - IpProtocol: "-1" + CidrIp: 0.0.0.0/0 SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 From 392c55ce0139f693e040312c280f8ee3ff9b4bee Mon Sep 17 00:00:00 2001 From: Bala Bala Date: Fri, 12 Jan 2024 15:51:27 -0500 Subject: [PATCH 12/13] Update template.yaml POWERTOOLS_LOG_LEVEL --- alb-lambda-rest-api-sam-py/template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alb-lambda-rest-api-sam-py/template.yaml b/alb-lambda-rest-api-sam-py/template.yaml index 62048efc3..3cd4a7349 100644 --- a/alb-lambda-rest-api-sam-py/template.yaml +++ b/alb-lambda-rest-api-sam-py/template.yaml @@ -25,7 +25,7 @@ Globals: Environment: Variables: POWERTOOLS_SERVICE_NAME: alb-lambda-rest-api-sam-py - LOG_LEVEL: DEBUG + POWERTOOLS_LOG_LEVEL: INFO Api: TracingEnabled: true Resources: From 2c1071d891cfc26c7278c5e684fc2bd9ba150de1 Mon Sep 17 00:00:00 2001 From: Ben <9841563+bfreiberg@users.noreply.github.com> Date: Sat, 13 Jan 2024 09:25:17 +0100 Subject: [PATCH 13/13] Add final pattern file --- .../alb-lambda-rest-api-sam-py.json | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 alb-lambda-rest-api-sam-py/alb-lambda-rest-api-sam-py.json diff --git a/alb-lambda-rest-api-sam-py/alb-lambda-rest-api-sam-py.json b/alb-lambda-rest-api-sam-py/alb-lambda-rest-api-sam-py.json new file mode 100644 index 000000000..51668843f --- /dev/null +++ b/alb-lambda-rest-api-sam-py/alb-lambda-rest-api-sam-py.json @@ -0,0 +1,95 @@ +{ + "title": "ALB with route-based listener rules to AWS Lambda", + "description": "This pattern creates an Application Load Balancer with route-based listener rules, paired with an AWS Lambda function as the target.", + "language": "Python", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This setup orchestrates the deployment of an Application Load Balancer, configures path-based routes directing traffic to a Python-based AWS Lambda function, and leverages the AWS Lambda Powertools for Python library. The Lambda function, serving as the target, records details of the incoming ALB event, along with the API and context objects, logging them to an Amazon CloudWatch Logs log group and Amazon X-Ray." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/alb-lambda-rest-api-sam-py", + "templateURL": "serverless-patterns/alb-lambda-rest-api-sam-py", + "projectFolder": "alb-lambda-rest-api-sam-py", + "templateFile": "template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "AWS CLI", + "link": "https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html" + }, + { + "text": "SAM CLI", + "link": "https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html" + }, + { + "text": "Python 3", + "link": "https://www.python.org/downloads/" + }, + { + "text": "AWS SAM build image for Python 3.9", + "link": "https://gallery.ecr.aws/sam/build-python3.9" + }, + { + "text": "Docker Desktop", + "link": "https://www.docker.com/products/docker-desktop/" + }, + { + "text": "Using AWS Lambda with an Application Load Balancer", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html" + }, + { + "text": "Powertools for AWS Lambda (Python)", + "link": "https://docs.powertools.aws.dev/lambda/python/latest/" + } + ] + }, + "deploy": { + "text": [ + "sam validate && sam build && sam deploy --guided" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "sam delete" + ] + }, + "authors": [ + { + "name": "Balasubrahmanya Balakrishna", + "image": "https://github.com/bb245/balabala/blob/main/balabala.png", + "bio": "Senior Lead Software Engineer, Capital One Services, LLC.", + "linkedin": "bala~bala" + } + ], + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "alb", + "label": "Application Load Balancer" + }, + "icon2": { + "x": 80, + "y": 50, + "service": "lambda", + "label": "AWS Lambda" + }, + "line1": { + "from": "icon1", + "to": "icon2", + "label": "route-based listener" + } + } +}