From 0f0ab1c42fa162c729f7590c751626f4e2606b58 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 18 Aug 2024 18:14:57 -0400 Subject: [PATCH 01/20] WIP AWS deployment --- .gitignore | 4 +- aws/build_lambda_code.py | 84 ++++++++++++++++++++ aws/cloudformation.yml | 121 +++++++++++++++++++++++++++++ aws/index.py | 80 +++++++++++++++++++ imaginate_api/date/routes.py | 4 +- imaginate_api/schemas/date_info.py | 3 +- 6 files changed, 292 insertions(+), 4 deletions(-) create mode 100644 aws/build_lambda_code.py create mode 100644 aws/cloudformation.yml create mode 100644 aws/index.py diff --git a/.gitignore b/.gitignore index 199e786..39f53b9 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ **/__pycache__ .pytest_cache .ruff_cache -junit \ No newline at end of file +junit +aws/dependencies +*.zip \ No newline at end of file diff --git a/aws/build_lambda_code.py b/aws/build_lambda_code.py new file mode 100644 index 0000000..33b38f4 --- /dev/null +++ b/aws/build_lambda_code.py @@ -0,0 +1,84 @@ +import inspect +import re +import os +import subprocess +import shutil +import zipfile +from imaginate_api.date.routes import images_by_date +from imaginate_api.utils import build_result, calculate_date +from imaginate_api.schemas.date_info import DateInfo + + +CWD = os.path.dirname(os.path.realpath(__file__)) +LAMBDA_LIBRARIES = """import os +import json +from enum import Enum +from http import HTTPStatus +from base64 import b64encode + +# External libraries from pymongo: +from pymongo import MongoClient +from gridfs import GridFS +from bson.objectid import ObjectId +""" +LAMBDA_SETUP = """db_name = 'imaginate_dev' +conn_uri = os.environ.get('MONGO_TOKEN') +client = MongoClient(conn_uri) +db = client[db_name] +fs = GridFS(db) +""" +LAMBDA_FUNC = """def handler(event, context): + if event and 'queryStringParameters' in event and event['queryStringParameters'] and 'day' in event['queryStringParameters']: + return images_by_date(event['queryStringParameters']['day']) + else: + return {'statusCode': HTTPStatus.BAD_REQUEST, 'body': json.dumps('Invalid date')} +""" +LAMBDA_SUBS = { + "abort": "return {'statusCode': HTTPStatus.BAD_REQUEST, 'body': json.dumps('Invalid date')}", + "@bp.route": "", # Remove this from function decorator + "return jsonify": "return {'statusCode': HTTPStatus.OK, 'body': json.dumps(out)}", +} + + +# Meta-program our source function to substitute Flask related libraries +def edit_source_function(source_function: str) -> str: + for sub in LAMBDA_SUBS: + source_function = re.sub( + r"^(\s*)" + sub + r".*$", + r"\g<1>" + LAMBDA_SUBS[sub], + source_function, + flags=re.MULTILINE, + ) + return source_function.strip() + + +if __name__ == "__main__": + # The main function AWS Lambda will directly invoke + source_function = edit_source_function(inspect.getsource(images_by_date)) + + # Order all the required external code needed: helper functions, classes and source function + all_functions = [ + inspect.getsource(DateInfo), + inspect.getsource(build_result), + inspect.getsource(calculate_date), + source_function, + ] + + # Save a .py file of our Lambda function code (mainly for verification purposes) + with open("aws/index.py", "w") as f: + f.write(LAMBDA_LIBRARIES + "\n") # Libaries defined as constants + f.write(LAMBDA_SETUP + "\n") + f.write("\n".join(all_functions) + "\n\n") # Functions retrieved from source code + f.write(LAMBDA_FUNC) + + # Following documentation from here: + # https://www.mongodb.com/developer/products/atlas/awslambda-pymongo/ + subprocess.run("mkdir dependencies", shell=True, cwd=CWD) + subprocess.run( + "pip install --upgrade --target ./dependencies pymongo", shell=True, cwd=CWD + ) + shutil.make_archive("aws", "zip", "aws/dependencies") + zf = zipfile.ZipFile("aws.zip", "a") + zf.write("aws/index.py", "index.py") + zf.close() + print("aws.zip successfully saved at root directory!") diff --git a/aws/cloudformation.yml b/aws/cloudformation.yml new file mode 100644 index 0000000..ae66979 --- /dev/null +++ b/aws/cloudformation.yml @@ -0,0 +1,121 @@ +# Sourced from: https://gist.github.com/magnetikonline/c314952045eee8e8375b82bc7ec68e88 +AWSTemplateFormatVersion: "2010-09-09" +Description: Imaginate API Gateway and Lambda function + +Parameters: + apiGatewayName: + Type: String + Default: ImaginateApi + apiGatewayStageName: + Type: String + AllowedPattern: '[a-z0-9]+' + Default: call + apiGatewayHTTPMethod: + Type: String + Default: GET + lambdaFunctionName: + Type: String + AllowedPattern: '[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+' + Default: get-images + mongoToken: + Type: String + NoEcho: true + +Resources: + apiGateway: + Type: AWS::ApiGateway::RestApi + Properties: + Description: Example API Gateway + EndpointConfiguration: + Types: + - REGIONAL + Name: !Ref apiGatewayName + + apiGatewayRootMethod: + Type: AWS::ApiGateway::Method + Properties: + AuthorizationType: NONE + RequestParameters: + method.request.querystring.day: true + HttpMethod: !Ref apiGatewayHTTPMethod + Integration: + IntegrationHttpMethod: POST + Type: AWS_PROXY + RequestParameters: + integration.request.querystring.day: method.request.querystring.day + Uri: !Sub + - arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations + - lambdaArn: !GetAtt lambdaFunction.Arn + ResourceId: !GetAtt apiGateway.RootResourceId + RestApiId: !Ref apiGateway + + apiGatewayDeployment: + Type: AWS::ApiGateway::Deployment + DependsOn: + - apiGatewayRootMethod + Properties: + RestApiId: !Ref apiGateway + StageName: !Ref apiGatewayStageName + + lambdaFunction: + Type: AWS::Lambda::Function + Properties: + Code: + ZipFile: | + def handler(event, context): + pass + Description: Get images by date + FunctionName: !Ref lambdaFunctionName + Handler: index.handler + Role: !GetAtt lambdaIAMRole.Arn + Runtime: python3.12 + Environment: + Variables: + MONGO_TOKEN: !Ref mongoToken + + lambdaApiGatewayInvoke: + Type: AWS::Lambda::Permission + Properties: + Action: lambda:InvokeFunction + FunctionName: !GetAtt lambdaFunction.Arn + Principal: apigateway.amazonaws.com + # NOTE: If the route is NOT at API Gateway root, `SourceArn` would take the form of: + # arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/${apiGatewayStageName}/${apiGatewayHTTPMethod}/PATH_PART + SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/${apiGatewayStageName}/${apiGatewayHTTPMethod}/ + + lambdaIAMRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Action: + - sts:AssumeRole + Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Policies: + - PolicyDocument: + Version: "2012-10-17" + Statement: + - Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Effect: Allow + Resource: + - !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:* + PolicyName: lambda + + lambdaLogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Sub /aws/lambda/${lambdaFunctionName} + RetentionInDays: 90 + +Outputs: + apiGatewayInvokeURL: + Value: !Sub https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName} + lambdaArn: + Value: !GetAtt lambdaFunction.Arn \ No newline at end of file diff --git a/aws/index.py b/aws/index.py new file mode 100644 index 0000000..b0d3765 --- /dev/null +++ b/aws/index.py @@ -0,0 +1,80 @@ +import os +import json +from enum import Enum +from http import HTTPStatus +from base64 import b64encode + +# External libraries from pymongo: +from pymongo import MongoClient +from gridfs import GridFS +from bson.objectid import ObjectId + +db_name = "imaginate_dev" +conn_uri = os.environ.get("MONGO_TOKEN") +client = MongoClient(conn_uri) +db = client[db_name] +fs = GridFS(db) + + +class DateInfo(Enum): + START_DATE = 1722484800 # Timestamp for August 1st, 2024 + SECONDS_PER_DAY = 86400 + + +def build_result( + _id: ObjectId, real: bool, date: int, theme: str, status: str, filename: str +): + return { + "filename": filename, + "url": "image/read/" + str(_id), + "real": real, + "date": date, + "theme": theme, + "status": status, + } + + +def calculate_date(day: str | int | None): + if day is not None: + if isinstance(day, str): + day = int(day) + if day >= DateInfo.START_DATE.value: + return day + return DateInfo.START_DATE.value + day * DateInfo.SECONDS_PER_DAY.value + return None + + +def images_by_date(day): + try: + date = calculate_date(day) + if not date: + return {"statusCode": HTTPStatus.BAD_REQUEST, "body": json.dumps("Invalid date")} + except ValueError: + return {"statusCode": HTTPStatus.BAD_REQUEST, "body": json.dumps("Invalid date")} + + res = fs.find({"date": date}) + out = [] + for document in res: + current_res = build_result( + document._id, + document.real, + document.date, + document.theme, + document.status, + document.filename, + ) + encoded_data = b64encode(document.read()) + current_res["data"] = encoded_data.decode("utf-8") + out.append(current_res) + return {"statusCode": HTTPStatus.OK, "body": json.dumps(out)} + + +def handler(event, context): + if ( + event + and "queryStringParameters" in event + and "day" in event["queryStringParameters"] + ): + return images_by_date(event["queryStringParameters"]["day"]) + else: + return {"statusCode": HTTPStatus.BAD_REQUEST, "body": json.dumps("Invalid date")} diff --git a/imaginate_api/date/routes.py b/imaginate_api/date/routes.py index 7fae81b..96dcd11 100644 --- a/imaginate_api/date/routes.py +++ b/imaginate_api/date/routes.py @@ -2,7 +2,7 @@ from imaginate_api.extensions import fs from imaginate_api.utils import build_result, calculate_date from http import HTTPStatus -import base64 +from base64 import b64encode bp = Blueprint("date", __name__) @@ -28,7 +28,7 @@ def images_by_date(day): document.status, document.filename, ) - encoded_data = base64.b64encode(document.read()) + encoded_data = b64encode(document.read()) current_res["data"] = encoded_data.decode("utf-8") out.append(current_res) return jsonify(out) diff --git a/imaginate_api/schemas/date_info.py b/imaginate_api/schemas/date_info.py index 97534d5..93f3fe3 100644 --- a/imaginate_api/schemas/date_info.py +++ b/imaginate_api/schemas/date_info.py @@ -1,5 +1,6 @@ from enum import Enum + class DateInfo(Enum): - START_DATE = 1722484800 # timestamp for august 1st, 2024 + START_DATE = 1722484800 # Timestamp for August 1st, 2024 SECONDS_PER_DAY = 86400 From 04d812a290e55d689107c6d1f0a99e02faa1b351 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 25 Aug 2024 22:31:35 -0400 Subject: [PATCH 02/20] Untested AWS Cloudformation templates --- aws/billing.yml | 92 ++++++++++++++++++++++++++ aws/build_lambda_code.py | 20 +++--- aws/{cloudformation.yml => deploy.yml} | 6 +- aws/index.py | 3 +- aws/roles.yml | 55 +++++++++++++++ 5 files changed, 164 insertions(+), 12 deletions(-) create mode 100644 aws/billing.yml rename aws/{cloudformation.yml => deploy.yml} (96%) create mode 100644 aws/roles.yml diff --git a/aws/billing.yml b/aws/billing.yml new file mode 100644 index 0000000..1221e9c --- /dev/null +++ b/aws/billing.yml @@ -0,0 +1,92 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: CloudFormation template to monitor AWS Free Tier usage, budget limits, and billing thresholds, with email notifications. + +Parameters: + budgetLimit: + Type: Number + Default: 20 + Description: Monthly limit - will be notified when exceeding 75% and 100% of input value in CAD + billingThreshold: + Type: Number + Default: 10 + Description: Outstanding charges - will be notified when exceeding input value in CAD + emailAddress: + Type: String + AllowedPattern: '[^@]+@[^@]+\.[^@]+' + Default: email@example.com + +Resources: + notificationTopic: + Type: AWS::SNS::Topic + Properties: + TopicName: BillingAndUsageNotifications + Subscription: + - Endpoint: !Ref emailAddress + Protocol: email + + freeTierAlarm: + Type: AWS::CloudWatch::Alarm + Properties: + AlarmName: FreeTierExceeded + AlarmDescription: Triggers when AWS Free Tier limits are exceeded + MetricName: EstimatedCharges + Namespace: AWS/Billing + Statistic: Maximum + Period: 3600 # Check every hour + EvaluationPeriods: 1 + Threshold: 0.01 + ComparisonOperator: GreaterThanThreshold + AlarmActions: + - Ref: notificationTopic + Dimensions: + - Name: Currency + Value: CAD + + billingAlarm: + Type: AWS::CloudWatch::Alarm + Properties: + AlarmName: BillingThresholdExceeded + AlarmDescription: Triggers when the AWS bill exceeds the specified threshold + MetricName: EstimatedCharges + Namespace: AWS/Billing + Statistic: Maximum + Period: 3600 # Check every hour + EvaluationPeriods: 1 + Threshold: !Ref billingThreshold + ComparisonOperator: GreaterThanOrEqualToThreshold + AlarmActions: + - Ref: notificationTopic + Dimensions: + - Name: Currency + Value: CAD + + monthlyBudget: + Type: AWS::Budgets::Budget + Properties: + Budget: + BudgetName: MonthlyBudgetLimit + BudgetLimit: + Amount: !Ref budgetLimit + Unit: CAD + TimeUnit: MONTHLY + BudgetType: COST + CostFilters: {} + CostTypes: + IncludeTax: true + IncludeSubscription: true + UseBlended: false + NotificationsWithSubscribers: + - Notification: + NotificationType: ACTUAL + ComparisonOperator: GREATER_THAN + Threshold: 75 # 75% of budget is used + Subscribers: + - SubscriptionType: EMAIL + Address: !Ref emailAddress + - Notification: + NotificationType: ACTUAL + ComparisonOperator: GREATER_THAN + Threshold: 100 # 100% of budget is used + Subscribers: + - SubscriptionType: EMAIL + Address: !Ref emailAddress diff --git a/aws/build_lambda_code.py b/aws/build_lambda_code.py index 33b38f4..a44c40d 100644 --- a/aws/build_lambda_code.py +++ b/aws/build_lambda_code.py @@ -9,6 +9,7 @@ from imaginate_api.schemas.date_info import DateInfo +DIR = "aws" CWD = os.path.dirname(os.path.realpath(__file__)) LAMBDA_LIBRARIES = """import os import json @@ -21,7 +22,7 @@ from gridfs import GridFS from bson.objectid import ObjectId """ -LAMBDA_SETUP = """db_name = 'imaginate_dev' +LAMBDA_SETUP = """db_name = 'imaginate_dev' # Database names: ['imaginate_dev', 'imaginate_prod'] conn_uri = os.environ.get('MONGO_TOKEN') client = MongoClient(conn_uri) db = client[db_name] @@ -35,7 +36,7 @@ """ LAMBDA_SUBS = { "abort": "return {'statusCode': HTTPStatus.BAD_REQUEST, 'body': json.dumps('Invalid date')}", - "@bp.route": "", # Remove this from function decorator + "@bp.route": "", # Remove function decorator entirely "return jsonify": "return {'statusCode': HTTPStatus.OK, 'body': json.dumps(out)}", } @@ -64,21 +65,24 @@ def edit_source_function(source_function: str) -> str: source_function, ] - # Save a .py file of our Lambda function code (mainly for verification purposes) - with open("aws/index.py", "w") as f: + # Save our Lambda function code + with open(f"{DIR}/index.py", "w") as f: f.write(LAMBDA_LIBRARIES + "\n") # Libaries defined as constants f.write(LAMBDA_SETUP + "\n") f.write("\n".join(all_functions) + "\n\n") # Functions retrieved from source code f.write(LAMBDA_FUNC) + # Format our Lambda funtion code with ruff before packaging + subprocess.run("ruff format index.py", shell=True, cwd=CWD) + # Following documentation from here: # https://www.mongodb.com/developer/products/atlas/awslambda-pymongo/ subprocess.run("mkdir dependencies", shell=True, cwd=CWD) subprocess.run( "pip install --upgrade --target ./dependencies pymongo", shell=True, cwd=CWD ) - shutil.make_archive("aws", "zip", "aws/dependencies") - zf = zipfile.ZipFile("aws.zip", "a") - zf.write("aws/index.py", "index.py") + shutil.make_archive(f"{DIR}/aws", "zip", f"{DIR}/dependencies") + zf = zipfile.ZipFile(f"{DIR}/aws.zip", "a") + zf.write(f"{DIR}/index.py", "index.py") zf.close() - print("aws.zip successfully saved at root directory!") + print(f"aws.zip successfully saved in {DIR} directory") diff --git a/aws/cloudformation.yml b/aws/deploy.yml similarity index 96% rename from aws/cloudformation.yml rename to aws/deploy.yml index ae66979..fb101dd 100644 --- a/aws/cloudformation.yml +++ b/aws/deploy.yml @@ -1,6 +1,6 @@ # Sourced from: https://gist.github.com/magnetikonline/c314952045eee8e8375b82bc7ec68e88 AWSTemplateFormatVersion: "2010-09-09" -Description: Imaginate API Gateway and Lambda function +Description: CloudFormation template to build an API Gateway and Lambda function Parameters: apiGatewayName: @@ -16,7 +16,7 @@ Parameters: lambdaFunctionName: Type: String AllowedPattern: '[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+' - Default: get-images + Default: GetImages mongoToken: Type: String NoEcho: true @@ -118,4 +118,4 @@ Outputs: apiGatewayInvokeURL: Value: !Sub https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName} lambdaArn: - Value: !GetAtt lambdaFunction.Arn \ No newline at end of file + Value: !GetAtt lambdaFunction.Arn diff --git a/aws/index.py b/aws/index.py index b0d3765..77a09e2 100644 --- a/aws/index.py +++ b/aws/index.py @@ -9,7 +9,7 @@ from gridfs import GridFS from bson.objectid import ObjectId -db_name = "imaginate_dev" +db_name = "imaginate_dev" # Database names: ['imaginate_dev', 'imaginate_prod'] conn_uri = os.environ.get("MONGO_TOKEN") client = MongoClient(conn_uri) db = client[db_name] @@ -73,6 +73,7 @@ def handler(event, context): if ( event and "queryStringParameters" in event + and event["queryStringParameters"] and "day" in event["queryStringParameters"] ): return images_by_date(event["queryStringParameters"]["day"]) diff --git a/aws/roles.yml b/aws/roles.yml new file mode 100644 index 0000000..4ca251f --- /dev/null +++ b/aws/roles.yml @@ -0,0 +1,55 @@ +AWSTemplateFormatVersion: "2010-09-09" +Description: CloudFormation template to build an API Gateway and Lambda function + +Parameters: + devUserName: + Type: String + AllowedPattern: '[a-z0-9]+' + Default: dev + +Resources: + devUser: + Type: AWS::IAM::User + Properties: + UserName: !Ref devUserName + Policies: + - PolicyName: AssumeLambdaRolePolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: sts:AssumeRole + Resource: !GetAtt lambdaFullAccessRole.Arn + + devUserAccessKey: + Type: AWS::IAM::AccessKey + Properties: + UserName: !Ref devUser + Status: Active + + lambdaFullAccessRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: sts:AssumeRole + - Effect: Allow + Principal: + AWS: !GetAtt devUser.Arn + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/AWSLambda_FullAccess + RoleName: LambdaFullAccessRole + +Outputs: + devUserAccessKeyId: + Value: !Ref DevUserAccessKey + devUserAccessKeyPass: + Value: !GetAtt DevUserAccessKey.SecretAccessKey + lambdaFullAccessRoleArn: + Value: !GetAtt lambdaFullAccessRole.Arn \ No newline at end of file From af31714b85b41c0c2721c4e1cf2b875e01f8dfc1 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:03:07 -0400 Subject: [PATCH 03/20] AWS verified templates + Actions update --- .github/workflows/deploy.yml | 57 ++++++++++++++++++++++++++++++++++++ .gitignore | 3 +- aws/SETUP.md | 37 +++++++++++++++++++++++ aws/billing.yml | 13 ++++---- aws/build_lambda_code.py | 3 +- aws/deploy.sh | 13 ++++++++ aws/deploy.yml | 5 +--- aws/roles.yml | 39 ++++++++++++++---------- 8 files changed, 144 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 aws/SETUP.md create mode 100644 aws/deploy.sh diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..7a6a4ba --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,57 @@ +name: Deploy Pipeline +on: [workflow_dispatch] +jobs: + deploy: + name: Deploy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + - name: Display Python version + run: python -c "import sys; print(sys.version)" + - name: Restore cached .venv + uses: actions/cache/restore@v4 + id: cache-venv + with: + key: venv-${{ runner.os }}-${{ hashFiles('poetry.lock') }} + path: .venv + - name: Setup environment + run: | + python -m pip install --upgrade pip + pip install poetry + poetry config --list + - name: Install dependencies + if: steps.cache-venv.outputs.cache-hit != 'true' + run: poetry install --no-interaction --no-root + - name: Cache .venv + if: steps.cache-venv.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + key: venv-${{ runner.os }}-${{ hashFiles('poetry.lock') }} + path: .venv + - name: Create .env + uses: SpicyPizza/create-envfile@v2.0 + with: + envkey_DEV: "dev" + envkey_MONGO_TOKEN: ${{ secrets.MONGO_TOKEN }} + file_name: .env + - name: AWS Setup + run: | + mkdir -p ~/.aws + cat > ~/.aws/config << EOF + [profile dev] + role_arn = ${{ secrets.LAMBDA_ARN }} + source_profile = default + EOF + cat > ~/.aws/credentials << EOF + [default] + aws_access_key_id = ${{ secrets.DEV_ID }} + aws_secret_access_key = ${{ secrets.DEV_KEY }} + EOF + - name: Build Lambda code + run: python aws/build_lambda_code.py + - name: Deploy stack + run: ./aws/deploy.sh \ No newline at end of file diff --git a/.gitignore b/.gitignore index 39f53b9..8a8f223 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ .ruff_cache junit aws/dependencies -*.zip \ No newline at end of file +*.zip +packaged* \ No newline at end of file diff --git a/aws/SETUP.md b/aws/SETUP.md new file mode 100644 index 0000000..9eb7576 --- /dev/null +++ b/aws/SETUP.md @@ -0,0 +1,37 @@ +# AWS Guide + +This guide will walk you through how to utilize the CloudFormation templates used to deploy this application! + +## Prerequisites +1. Download the AWS CLI following [this documentation](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) + +## First Time Setup +1. Build the stacks corresponding to the files `roles.yml` and `billing.yml` through the AWS Cloud Console. +2. Determine the `dev` access credentials and `lambda_arn` from the `roles.yml` stack output for the next step +3. Configure the `~/.aws/config` and `~/.aws/credentials` files with the necessary data. The location of these files can be determined [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-where): + +`~/.aws/config`: +``` +[profile dev] +role_arn = +source_profile = default +``` + +`~/.aws/credentials`: +``` +[default] +aws_access_key_id = +aws_secret_access_key = +``` +4. Add the following secrets to GitHub: `LAMBDA_ARN`, `DEV_ID`, `DEV_KEY` + +**NOTE**: Upon building the `billing.yml` stack you should receive a confirmation email to verify the notification subscription + +## Deploying / Updating Stack +**NOTE:** These commands must be run from the root directory +1. Build the updated Lambda code with: `python aws/build_lambda_code.py` which will create a `aws.zip` file +2. Deploy the code with: `./aws/deploy.sh` + + +## Documentation +- [AWS authentication and access credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-authentication-user.html) \ No newline at end of file diff --git a/aws/billing.yml b/aws/billing.yml index 1221e9c..8b81334 100644 --- a/aws/billing.yml +++ b/aws/billing.yml @@ -5,15 +5,18 @@ Parameters: budgetLimit: Type: Number Default: 20 - Description: Monthly limit - will be notified when exceeding 75% and 100% of input value in CAD + Description: Monthly limit - will be notified when exceeding 75% and 100% of input value in USD billingThreshold: Type: Number Default: 10 - Description: Outstanding charges - will be notified when exceeding input value in CAD + Description: Outstanding charges - will be notified when exceeding input value in USD emailAddress: Type: String AllowedPattern: '[^@]+@[^@]+\.[^@]+' Default: email@example.com + currency: + Type: String + Default: USD Resources: notificationTopic: @@ -40,7 +43,7 @@ Resources: - Ref: notificationTopic Dimensions: - Name: Currency - Value: CAD + Value: !Ref currency billingAlarm: Type: AWS::CloudWatch::Alarm @@ -58,7 +61,7 @@ Resources: - Ref: notificationTopic Dimensions: - Name: Currency - Value: CAD + Value: !Ref currency monthlyBudget: Type: AWS::Budgets::Budget @@ -67,7 +70,7 @@ Resources: BudgetName: MonthlyBudgetLimit BudgetLimit: Amount: !Ref budgetLimit - Unit: CAD + Unit: !Ref currency TimeUnit: MONTHLY BudgetType: COST CostFilters: {} diff --git a/aws/build_lambda_code.py b/aws/build_lambda_code.py index a44c40d..7deb498 100644 --- a/aws/build_lambda_code.py +++ b/aws/build_lambda_code.py @@ -9,6 +9,7 @@ from imaginate_api.schemas.date_info import DateInfo +ENV = "dev" DIR = "aws" CWD = os.path.dirname(os.path.realpath(__file__)) LAMBDA_LIBRARIES = """import os @@ -22,7 +23,7 @@ from gridfs import GridFS from bson.objectid import ObjectId """ -LAMBDA_SETUP = """db_name = 'imaginate_dev' # Database names: ['imaginate_dev', 'imaginate_prod'] +LAMBDA_SETUP = f"""db_name = 'imaginate_{ENV}' # Database names: ['imaginate_dev', 'imaginate_prod'] conn_uri = os.environ.get('MONGO_TOKEN') client = MongoClient(conn_uri) db = client[db_name] diff --git a/aws/deploy.sh b/aws/deploy.sh new file mode 100644 index 0000000..a3ecbb6 --- /dev/null +++ b/aws/deploy.sh @@ -0,0 +1,13 @@ +#!/bin/bash +BUCKET_NAME="imaginate-templates-bucket" +STACK_NAME="imaginate" +REGION="us-east-1" +PROFILE="dev" + +# Read environment variables +source .env + +# AWS build/deploy +aws s3 mb s3://$BUCKET_NAME --region $REGION --profile $PROFILE +aws cloudformation package --template-file aws/deploy.yml --s3-bucket $BUCKET_NAME --output-template-file aws/packaged-deploy.yml --profile $PROFILE +aws cloudformation deploy --template-file aws/packaged-deploy.yml --stack-name $STACK_NAME --region $REGION --capabilities CAPABILITY_NAMED_IAM --profile $PROFILE --parameter-overrides mongoToken=$MONGO_TOKEN diff --git a/aws/deploy.yml b/aws/deploy.yml index fb101dd..3c32434 100644 --- a/aws/deploy.yml +++ b/aws/deploy.yml @@ -60,10 +60,7 @@ Resources: lambdaFunction: Type: AWS::Lambda::Function Properties: - Code: - ZipFile: | - def handler(event, context): - pass + Code: aws.zip Description: Get images by date FunctionName: !Ref lambdaFunctionName Handler: index.handler diff --git a/aws/roles.yml b/aws/roles.yml index 4ca251f..2a78129 100644 --- a/aws/roles.yml +++ b/aws/roles.yml @@ -10,22 +10,23 @@ Parameters: Resources: devUser: Type: AWS::IAM::User + DependsOn: + - devUserSecret Properties: UserName: !Ref devUserName - Policies: - - PolicyName: AssumeLambdaRolePolicy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: sts:AssumeRole - Resource: !GetAtt lambdaFullAccessRole.Arn + LoginProfile: + Password: !Sub '{{resolve:secretsmanager:${devUserName}Password}}' + PasswordResetRequired: false - devUserAccessKey: - Type: AWS::IAM::AccessKey + devUserSecret: + Type: AWS::SecretsManager::Secret Properties: - UserName: !Ref devUser - Status: Active + Name: !Sub ${devUserName}Password + GenerateSecretString: + PasswordLength: 32 + ExcludeCharacters: '"@/\' + IncludeSpace: false + RequireEachIncludedType: true lambdaFullAccessRole: Type: AWS::IAM::Role @@ -43,13 +44,21 @@ Resources: AWS: !GetAtt devUser.Arn Action: sts:AssumeRole ManagedPolicyArns: - - arn:aws:iam::aws:policy/AWSLambda_FullAccess + - arn:aws:iam::aws:policy/AdministratorAccess RoleName: LambdaFullAccessRole + + devUserAccessKey: + Type: AWS::IAM::AccessKey + Properties: + UserName: !Ref devUser + Status: Active Outputs: devUserAccessKeyId: - Value: !Ref DevUserAccessKey + Value: !Ref devUserAccessKey devUserAccessKeyPass: - Value: !GetAtt DevUserAccessKey.SecretAccessKey + Value: !GetAtt devUserAccessKey.SecretAccessKey + devUserName: + Value: !Ref devUser lambdaFullAccessRoleArn: Value: !GetAtt lambdaFullAccessRole.Arn \ No newline at end of file From ac8e885eb1c4b8f7c363b7a0d7d1dc7aba8d8a36 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:09:19 -0400 Subject: [PATCH 04/20] Bandaid for testing --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7a6a4ba..a71bf1b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,5 +1,5 @@ name: Deploy Pipeline -on: [workflow_dispatch] +on: [workflow_dispatch, pull_request] jobs: deploy: name: Deploy From 1b7f96d8a6ba5d4f88955b4e7416330df646e779 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:17:24 -0400 Subject: [PATCH 05/20] Update --- aws/build_lambda_code.py | 5 +++++ imaginate_api/__init__.py | 0 2 files changed, 5 insertions(+) create mode 100644 imaginate_api/__init__.py diff --git a/aws/build_lambda_code.py b/aws/build_lambda_code.py index 7deb498..cc7611a 100644 --- a/aws/build_lambda_code.py +++ b/aws/build_lambda_code.py @@ -1,3 +1,8 @@ +import sys + +sys.path.append( + "." +) # Adds all root directories as a package, which in our case is: imaginate_api import inspect import re import os diff --git a/imaginate_api/__init__.py b/imaginate_api/__init__.py new file mode 100644 index 0000000..e69de29 From 260f95589a95c1a4604fcb62a28a0052c2a347ec Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:25:15 -0400 Subject: [PATCH 06/20] Update --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a71bf1b..7cf1d6e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -52,6 +52,6 @@ jobs: aws_secret_access_key = ${{ secrets.DEV_KEY }} EOF - name: Build Lambda code - run: python aws/build_lambda_code.py + run: poetry run python aws/build_lambda_code.py - name: Deploy stack run: ./aws/deploy.sh \ No newline at end of file From 3962c49cf91b83fab6d526f2092df88560573fbe Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:34:47 -0400 Subject: [PATCH 07/20] Update --- .github/workflows/deploy.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7cf1d6e..f080893 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -54,4 +54,7 @@ jobs: - name: Build Lambda code run: poetry run python aws/build_lambda_code.py - name: Deploy stack - run: ./aws/deploy.sh \ No newline at end of file + shell: bash + run: | + chmod +x ./aws/deploy.sh + ./aws/deploy.sh \ No newline at end of file From 3710e758a38c3547f328265835e69ad523595a61 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:38:03 -0400 Subject: [PATCH 08/20] Update --- .github/workflows/deploy.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f080893..c053daf 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,6 +23,13 @@ jobs: python -m pip install --upgrade pip pip install poetry poetry config --list + - name: Install AWS CLI V2 + run: | + curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip + unzip -q /tmp/awscliv2.zip -d /tmp + rm /tmp/awscliv2.zip + sudo /tmp/aws/install --update + rm -rf /tmp/aws/ - name: Install dependencies if: steps.cache-venv.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root From dc9a2f876d7a2f14e6fac1df899d5b164ce88cb7 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:52:58 -0400 Subject: [PATCH 09/20] Update logging --- aws/deploy.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aws/deploy.sh b/aws/deploy.sh index a3ecbb6..c145315 100644 --- a/aws/deploy.sh +++ b/aws/deploy.sh @@ -8,6 +8,10 @@ PROFILE="dev" source .env # AWS build/deploy +echo "Fetching bucket..." aws s3 mb s3://$BUCKET_NAME --region $REGION --profile $PROFILE +echo "Packaging..." aws cloudformation package --template-file aws/deploy.yml --s3-bucket $BUCKET_NAME --output-template-file aws/packaged-deploy.yml --profile $PROFILE +echo "Deploying..." +ls aws aws cloudformation deploy --template-file aws/packaged-deploy.yml --stack-name $STACK_NAME --region $REGION --capabilities CAPABILITY_NAMED_IAM --profile $PROFILE --parameter-overrides mongoToken=$MONGO_TOKEN From ed89723fb8006e7a91e74fb6805be7aa44440c62 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 21:56:57 -0400 Subject: [PATCH 10/20] Deploy --- aws/deploy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/deploy.sh b/aws/deploy.sh index c145315..f6e5b71 100644 --- a/aws/deploy.sh +++ b/aws/deploy.sh @@ -11,7 +11,7 @@ source .env echo "Fetching bucket..." aws s3 mb s3://$BUCKET_NAME --region $REGION --profile $PROFILE echo "Packaging..." -aws cloudformation package --template-file aws/deploy.yml --s3-bucket $BUCKET_NAME --output-template-file aws/packaged-deploy.yml --profile $PROFILE +aws cloudformation package --template-file aws/deploy.yml --s3-bucket $BUCKET_NAME --output-template-file aws/packaged-deploy.yml --region $REGION --profile $PROFILE echo "Deploying..." ls aws -aws cloudformation deploy --template-file aws/packaged-deploy.yml --stack-name $STACK_NAME --region $REGION --capabilities CAPABILITY_NAMED_IAM --profile $PROFILE --parameter-overrides mongoToken=$MONGO_TOKEN +aws cloudformation deploy --template-file aws/packaged-deploy.yml --stack-name $STACK_NAME --capabilities CAPABILITY_NAMED_IAM --region $REGION --profile $PROFILE --parameter-overrides mongoToken=$MONGO_TOKEN From d42b02130a94678bae7d3544eb5a1b54814e3c93 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 22:01:29 -0400 Subject: [PATCH 11/20] Deploy --- .github/workflows/deploy.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c053daf..5d40ade 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,13 +23,13 @@ jobs: python -m pip install --upgrade pip pip install poetry poetry config --list - - name: Install AWS CLI V2 - run: | - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip - unzip -q /tmp/awscliv2.zip -d /tmp - rm /tmp/awscliv2.zip - sudo /tmp/aws/install --update - rm -rf /tmp/aws/ + # - name: Install AWS CLI V2 + # run: | + # curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip + # unzip -q /tmp/awscliv2.zip -d /tmp + # rm /tmp/awscliv2.zip + # sudo /tmp/aws/install --update + # rm -rf /tmp/aws/ - name: Install dependencies if: steps.cache-venv.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root From 31c175c43522958ae64f379065d429409a54cd37 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 22:23:57 -0400 Subject: [PATCH 12/20] Deploy --- .github/workflows/deploy.yml | 9 +-------- aws/SETUP.md | 3 ++- aws/deploy.sh | 8 ++++++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5d40ade..c036d59 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -23,13 +23,6 @@ jobs: python -m pip install --upgrade pip pip install poetry poetry config --list - # - name: Install AWS CLI V2 - # run: | - # curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip - # unzip -q /tmp/awscliv2.zip -d /tmp - # rm /tmp/awscliv2.zip - # sudo /tmp/aws/install --update - # rm -rf /tmp/aws/ - name: Install dependencies if: steps.cache-venv.outputs.cache-hit != 'true' run: poetry install --no-interaction --no-root @@ -64,4 +57,4 @@ jobs: shell: bash run: | chmod +x ./aws/deploy.sh - ./aws/deploy.sh \ No newline at end of file + ./aws/deploy.sh ${{ secrets.MONGO_TOKEN }} \ No newline at end of file diff --git a/aws/SETUP.md b/aws/SETUP.md index 9eb7576..68c2cc9 100644 --- a/aws/SETUP.md +++ b/aws/SETUP.md @@ -34,4 +34,5 @@ aws_secret_access_key = ## Documentation -- [AWS authentication and access credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-authentication-user.html) \ No newline at end of file +- [AWS authentication and access credentials](https://docs.aws.amazon.com/cli/latest/userguide/cli-authentication-user.html) +- Viewing Lambda code: `aws lambda get-function --function-name --query 'Code.Location'` \ No newline at end of file diff --git a/aws/deploy.sh b/aws/deploy.sh index f6e5b71..5cc79cf 100644 --- a/aws/deploy.sh +++ b/aws/deploy.sh @@ -1,4 +1,6 @@ #!/bin/bash + +# Static variables BUCKET_NAME="imaginate-templates-bucket" STACK_NAME="imaginate" REGION="us-east-1" @@ -7,6 +9,12 @@ PROFILE="dev" # Read environment variables source .env +# Load first argument as MONGO_TOKEN if passed +if [ "$#" -lt 1 ] +then + MONGO_TOKEN=$1 +fi + # AWS build/deploy echo "Fetching bucket..." aws s3 mb s3://$BUCKET_NAME --region $REGION --profile $PROFILE From c3ea5509d405c09aa288a5ae2d3498fd2dc2ad13 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 22:28:14 -0400 Subject: [PATCH 13/20] Update --- aws/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/deploy.sh b/aws/deploy.sh index 5cc79cf..65dbac8 100644 --- a/aws/deploy.sh +++ b/aws/deploy.sh @@ -20,6 +20,6 @@ echo "Fetching bucket..." aws s3 mb s3://$BUCKET_NAME --region $REGION --profile $PROFILE echo "Packaging..." aws cloudformation package --template-file aws/deploy.yml --s3-bucket $BUCKET_NAME --output-template-file aws/packaged-deploy.yml --region $REGION --profile $PROFILE -echo "Deploying..." ls aws +echo "Deploying..." aws cloudformation deploy --template-file aws/packaged-deploy.yml --stack-name $STACK_NAME --capabilities CAPABILITY_NAMED_IAM --region $REGION --profile $PROFILE --parameter-overrides mongoToken=$MONGO_TOKEN From 48a68d2dbc7e41c74197513007e5c99318a698ae Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 22:42:24 -0400 Subject: [PATCH 14/20] Deploy --- aws/deploy.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/aws/deploy.sh b/aws/deploy.sh index 65dbac8..60b68e6 100644 --- a/aws/deploy.sh +++ b/aws/deploy.sh @@ -10,11 +10,17 @@ PROFILE="dev" source .env # Load first argument as MONGO_TOKEN if passed -if [ "$#" -lt 1 ] -then +if [ "$1" ]; then + echo "Loading MONGO_TOKEN..." MONGO_TOKEN=$1 fi +# Make sure MONGO_TOKEN is not empty +if [ "$MONGO_TOKEN" = "" ]; then + echo "MONGO_TOKEN is empty" + exit 1 +fi + # AWS build/deploy echo "Fetching bucket..." aws s3 mb s3://$BUCKET_NAME --region $REGION --profile $PROFILE From 20cadfea923f1225a498c163e40136144a53e423 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 22:48:45 -0400 Subject: [PATCH 15/20] Update --- .github/workflows/deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index c036d59..9ca2428 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,6 +12,8 @@ jobs: cache: "pip" - name: Display Python version run: python -c "import sys; print(sys.version)" + - name: Display AWS CLI version + run: aws --version - name: Restore cached .venv uses: actions/cache/restore@v4 id: cache-venv From 0aa5b45d086f84cee68d144b7551f07e55c425ed Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 22:55:08 -0400 Subject: [PATCH 16/20] Update --- aws/deploy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/deploy.sh b/aws/deploy.sh index 60b68e6..ef24e83 100644 --- a/aws/deploy.sh +++ b/aws/deploy.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -e # Static variables BUCKET_NAME="imaginate-templates-bucket" From 7c4f506ed5171061793acfeb965698d4c73a8773 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 22:59:41 -0400 Subject: [PATCH 17/20] Update --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9ca2428..e425d49 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -56,7 +56,7 @@ jobs: - name: Build Lambda code run: poetry run python aws/build_lambda_code.py - name: Deploy stack - shell: bash + shell: bash -l {0} run: | chmod +x ./aws/deploy.sh ./aws/deploy.sh ${{ secrets.MONGO_TOKEN }} \ No newline at end of file From c7b7d34bfcb559a0041de64c8b63610b6d97e987 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 23:06:50 -0400 Subject: [PATCH 18/20] Update --- aws/deploy.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aws/deploy.sh b/aws/deploy.sh index ef24e83..0f40b64 100644 --- a/aws/deploy.sh +++ b/aws/deploy.sh @@ -30,3 +30,5 @@ aws cloudformation package --template-file aws/deploy.yml --s3-bucket $BUCKET_NA ls aws echo "Deploying..." aws cloudformation deploy --template-file aws/packaged-deploy.yml --stack-name $STACK_NAME --capabilities CAPABILITY_NAMED_IAM --region $REGION --profile $PROFILE --parameter-overrides mongoToken=$MONGO_TOKEN +echo "Check status..." +aws cloudformation describe-stacks --stack-name $STACK_NAME --region $REGION --profile $PROFILE --query "Stacks[0].StackStatus" --output text From 53a6ff63f7627955a1dbd2a795e7f1733e118615 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 23:08:52 -0400 Subject: [PATCH 19/20] Update --- .github/workflows/deploy.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e425d49..f2c2596 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -59,4 +59,5 @@ jobs: shell: bash -l {0} run: | chmod +x ./aws/deploy.sh - ./aws/deploy.sh ${{ secrets.MONGO_TOKEN }} \ No newline at end of file + ./aws/deploy.sh ${{ secrets.MONGO_TOKEN }} + wait \ No newline at end of file From 48f8b2353225705033a518fdba381402f5eca961 Mon Sep 17 00:00:00 2001 From: Faisal Fawad Date: Sun, 1 Sep 2024 23:14:11 -0400 Subject: [PATCH 20/20] Pipeline working, removing bandaid --- .github/workflows/deploy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f2c2596..e2caf52 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,5 +1,5 @@ name: Deploy Pipeline -on: [workflow_dispatch, pull_request] +on: [workflow_dispatch] jobs: deploy: name: Deploy @@ -56,7 +56,7 @@ jobs: - name: Build Lambda code run: poetry run python aws/build_lambda_code.py - name: Deploy stack - shell: bash -l {0} + shell: bash run: | chmod +x ./aws/deploy.sh ./aws/deploy.sh ${{ secrets.MONGO_TOKEN }}