From 957ae5090ea2d1700548e5781ad3b764b768022f Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Sun, 28 Jan 2024 18:29:12 +0000 Subject: [PATCH] Update package and deplioy Using archive command plugin and AWS SAM --- todos-lambda/Package.swift | 2 +- .../App/Controllers/TodoController.swift | 6 +- todos-lambda/Sources/App/lambda.swift | 29 ++++-- todos-lambda/scripts/build-and-package.sh | 19 +--- todos-lambda/scripts/deploy.sh | 38 ++----- todos-lambda/scripts/package.sh | 26 ----- todos-lambda/scripts/sam.yml | 99 +++++++++++++++++++ todos-lambda/scripts/samconfig.toml | 31 ++++++ 8 files changed, 167 insertions(+), 83 deletions(-) delete mode 100755 todos-lambda/scripts/package.sh create mode 100644 todos-lambda/scripts/sam.yml create mode 100644 todos-lambda/scripts/samconfig.toml diff --git a/todos-lambda/Package.swift b/todos-lambda/Package.swift index de7d515b..3f671cee 100644 --- a/todos-lambda/Package.swift +++ b/todos-lambda/Package.swift @@ -9,7 +9,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0-alpha.1"), - .package(url: "https://github.com/hummingbird-project/hummingbird-lambda.git", branch: "2.x.x"), + .package(url: "https://github.com/hummingbird-project/hummingbird-lambda.git", branch: "2.x.x-request-headers"), .package(url: "https://github.com/soto-project/soto.git", from: "7.0.0-alpha"), ], targets: [ diff --git a/todos-lambda/Sources/App/Controllers/TodoController.swift b/todos-lambda/Sources/App/Controllers/TodoController.swift index 7c6a4e44..3d709157 100644 --- a/todos-lambda/Sources/App/Controllers/TodoController.swift +++ b/todos-lambda/Sources/App/Controllers/TodoController.swift @@ -23,16 +23,16 @@ struct TodoController { typealias Context = HBBasicLambdaRequestContext let dynamoDB: DynamoDB - let tableName = "hummingbird-todos" + let tableName: String func addRoutes(to group: HBRouterGroup) { group - .get(use: self.list) .post(use: self.create) - .delete(use: self.deleteAll) .get("{id}", use: self.get) + .get(use: self.list) .patch("{id}", use: self.updateId) .delete("{id}", use: self.deleteId) + .delete(use: self.deleteAll) } @Sendable func list(_ request: HBRequest, context: Context) async throws -> [Todo] { diff --git a/todos-lambda/Sources/App/lambda.swift b/todos-lambda/Sources/App/lambda.swift index 6c0e7107..38b36295 100644 --- a/todos-lambda/Sources/App/lambda.swift +++ b/todos-lambda/Sources/App/lambda.swift @@ -15,31 +15,32 @@ import AWSLambdaEvents import AWSLambdaRuntime import HummingbirdLambda +import Logging import SotoDynamoDB @main struct AppLambda: HBAPIGatewayLambda { let awsClient: AWSClient + let logger: Logger init(context: LambdaInitializationContext) { self.awsClient = AWSClient(httpClientProvider: .createNewWithEventLoopGroup(context.eventLoop)) + self.logger = context.logger } func buildResponder() -> some HBResponder { + let tableName = HBEnvironment.shared.get("TODOS_TABLE_NAME") ?? "hummingbird-todos" + self.logger.info("Using table \(tableName)") let dynamoDB = DynamoDB(client: awsClient, region: .euwest1) let router = HBRouter(context: Context.self) // middleware + router.middlewares.add(ErrorMiddleware()) router.middlewares.add(HBLogRequestsMiddleware(.debug)) - router.middlewares.add(HBCORSMiddleware( - allowOrigin: .originBased, - allowHeaders: [.contentType], - allowMethods: [.get, .options, .post, .delete, .patch] - )) router.get("/") { _, _ in return "Hello" } - TodoController(dynamoDB: dynamoDB).addRoutes(to: router.group("todos")) + TodoController(dynamoDB: dynamoDB, tableName: tableName).addRoutes(to: router.group("todos")) return router.buildResponder() } @@ -48,3 +49,19 @@ struct AppLambda: HBAPIGatewayLambda { try await self.awsClient.shutdown() } } + +struct ErrorMiddleware: HBMiddlewareProtocol { + func handle( + _ input: HBRequest, + context: Context, + next: (HBRequest, Context) async throws -> HBResponse + ) async throws -> HBResponse { + do { + return try await next(input, context) + } catch let error as HBHTTPError { + throw error + } catch { + throw HBHTTPError(.internalServerError, message: "Error: \(error)") + } + } +} diff --git a/todos-lambda/scripts/build-and-package.sh b/todos-lambda/scripts/build-and-package.sh index 734c38f0..dcd0e94d 100755 --- a/todos-lambda/scripts/build-and-package.sh +++ b/todos-lambda/scripts/build-and-package.sh @@ -13,20 +13,7 @@ ## ##===----------------------------------------------------------------------===## -set -eu +here=$(dirname "$0") -base=$(pwd) -executable=HummingbirdTodosLambda -swift_docker=swift:5.3-amazonlinux2 - -echo "-------------------------------------------------------------------------" -echo "building \"$executable\" lambda" -echo "-------------------------------------------------------------------------" -docker run --rm -v "$base":/src -w /src/ $swift_docker bash -cl "swift package update" -docker run --rm -v "$base":/src -w /src/ $swift_docker bash -cl "swift build --product $executable -c release -Xswiftc -static-stdlib" -echo "done" - -echo "-------------------------------------------------------------------------" -echo "packaging \"$executable\" lambda" -echo "-------------------------------------------------------------------------" -./scripts/package.sh $executable +cd "$here"/.. +swift package --disable-sandbox archive \ No newline at end of file diff --git a/todos-lambda/scripts/deploy.sh b/todos-lambda/scripts/deploy.sh index 213e6284..e4a5fed9 100755 --- a/todos-lambda/scripts/deploy.sh +++ b/todos-lambda/scripts/deploy.sh @@ -13,37 +13,13 @@ ## ##===----------------------------------------------------------------------===## -set -eu +here=$(dirname "$0") -export AWS_PROFILE=opticalaberration-admin_dev - -here=$(dirname $0) -# Lambda Function name -function_name=TodosBackend -executable_name=HummingbirdTodosLambda -policy_name="${function_name}-lamba-policy" -role_name="${function_name}-lamba-role" - -# does function already exist -if [ -n "$(aws lambda list-functions --output json --query 'Functions[*].FunctionName' | grep -w "$function_name")" ]; then - # function exists so just need to update it - echo "-------------------------------------------------------------------------" - echo "updating lambda \"$function_name\"" - echo "-------------------------------------------------------------------------" - aws lambda update-function-code --function "$function_name" --zip-file fileb://.build/lambda/"$executable_name"/lambda.zip - -else - # function does not exist need to create role to run it - echo "-------------------------------------------------------------------------" - echo "creating role \"$role_name\"" - echo "-------------------------------------------------------------------------" - assume_role_policy='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["sts:AssumeRole"],"Principal":{"Service":["lambda.amazonaws.com"]}}]}' - iam_role_arn=$(aws iam create-role --role-name "$role_name" --assume-role-policy-document "$assume_role_policy" --output text --query "Role.Arn") - aws iam put-role-policy --role-name "$role_name" --policy-name "$policy_name" --policy-document file://$here/policy.json - # create lambda - echo "-------------------------------------------------------------------------" - echo "creating lambda \"$function_name\"" - echo "-------------------------------------------------------------------------" - aws lambda create-function --function "$function_name" --role "$iam_role_arn" --runtime provided --memory-size 192 --timeout 20 --handler "$function_name" --zip-file fileb://.build/lambda/"$executable_name"/lambda.zip +if [ ! $(which sam) ]; then + echo "The deploy script requires AWS SAM." + echo "More information about AWS SAM and installation instructions can be found at https://aws.amazon.com/serverless/sam/" + exit -1 fi +cd "$here"/.. +sam deploy --stack-name hb-todos-lambda --resolve-s3 --template scripts/sam.yml $@ diff --git a/todos-lambda/scripts/package.sh b/todos-lambda/scripts/package.sh deleted file mode 100755 index 14185ea5..00000000 --- a/todos-lambda/scripts/package.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -##===----------------------------------------------------------------------===## -## -## This source file is part of the SwiftAWSLambdaRuntime open source project -## -## Copyright (c) 2020 Apple Inc. and the SwiftAWSLambdaRuntime project authors -## Licensed under Apache License v2.0 -## -## See LICENSE.txt for license information -## See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors -## -## SPDX-License-Identifier: Apache-2.0 -## -##===----------------------------------------------------------------------===## - -set -eu - -executable=$1 - -target=.build/lambda/$executable -rm -rf "$target" -mkdir -p "$target" -cp ".build/release/$executable" "$target/" -cd "$target" -ln -s "$executable" "bootstrap" -zip --symlinks lambda.zip * diff --git a/todos-lambda/scripts/sam.yml b/todos-lambda/scripts/sam.yml new file mode 100644 index 00000000..803d1785 --- /dev/null +++ b/todos-lambda/scripts/sam.yml @@ -0,0 +1,99 @@ +AWSTemplateFormatVersion : '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: A sample SAM template for deploying Hummingbird Lambda Todos function. + +Globals: + Function: + Timeout: 3 + MemorySize: 256 + +Resources: + # Todos Function + hbTodosFunction: + Type: AWS::Serverless::Function + Properties: + Handler: Provided + Runtime: provided.al2 + Architectures: + - arm64 + CodeUri: ../.build/plugins/AWSLambdaPackager/outputs/AWSLambdaPackager/App/App.zip + # Instructs new versions to be published to an alias named "live". + AutoPublishAlias: live + Events: + Hello: + Type: Api + Properties: + Path: / + Method: get + Create: + Type: Api + Properties: + Path: /todos + Method: post + Get: + Type: Api + Properties: + Path: /todos/{id} + Method: get + List: + Type: Api + Properties: + Path: /todos/ + Method: get + Patch: + Type: Api + Properties: + Path: /todos/{id} + Method: path + Delete: + Type: Api + Properties: + Path: /todos/{id} + Method: delete + DeleteAll: + Type: Api + Properties: + Path: /todos + Method: delete + Environment: + Variables: + TODOS_TABLE_NAME: !Ref TodosTable + Policies: + - DynamoDBCrudPolicy: # More info about SAM policy templates: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html + TableName: !Ref TodosTable + + TodosTable: + Type: AWS::Serverless::SimpleTable # More info about SimpleTable Resource: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-simpletable.html + Properties: + PrimaryKey: + Name: id + Type: String + +Outputs: + HelloFunctionApi: + Description: "API Gateway endpoint URL for Prod stage for Hello function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" + CreateFunctionApi: + Description: "API Gateway endpoint URL for Prod stage for Create function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos/" + GetFunctionApi: + Description: "API Gateway endpoint URL for Prod stage for Get function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos/{id}" + ListFunctionApi: + Description: "API Gateway endpoint URL for Prod stage for List function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos/" + PatchFunctionApi: + Description: "API Gateway endpoint URL for Prod stage for Patch function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos/{id}" + DeleteFunctionApi: + Description: "API Gateway endpoint URL for Prod stage for Delete function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos/{id}" + DeleteAllFunctionApi: + Description: "API Gateway endpoint URL for Prod stage for DeleteAll function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/todos/" + TodosFunction: + Description: "Todos function name" + Value: !GetAtt hbTodosFunction.Arn + TodosTable: + Description: "Hummingbird Todos Lambda Table" + Value: !GetAtt TodosTable.Arn diff --git a/todos-lambda/scripts/samconfig.toml b/todos-lambda/scripts/samconfig.toml new file mode 100644 index 00000000..f1ab8f8f --- /dev/null +++ b/todos-lambda/scripts/samconfig.toml @@ -0,0 +1,31 @@ +# More information about the configuration file can be found here: +# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html +version = 0.1 + +[default] +[default.global.parameters] +stack_name = "hb-todos-lambda" + +[default.build.parameters] +cached = true +parallel = true + +[default.validate.parameters] +lint = true + +[default.deploy.parameters] +capabilities = "CAPABILITY_IAM" +confirm_changeset = true +resolve_s3 = true + +[default.package.parameters] +resolve_s3 = true + +[default.sync.parameters] +watch = true + +[default.local_start_api.parameters] +warm_containers = "EAGER" + +[default.local_start_lambda.parameters] +warm_containers = "EAGER"