From ae9f6cd851177eef636079f3bd2152241b9c4dec Mon Sep 17 00:00:00 2001 From: Kevin Tran Date: Thu, 12 Mar 2026 13:59:46 -0500 Subject: [PATCH 1/3] feat: add ec2 launch template script + configure env variables --- .github/workflows/ec2_init.sh | 139 ++++++++++++++++++++++ CulinaryCommandApp/CulinaryCommand.csproj | 1 + CulinaryCommandApp/Program.cs | 23 ++-- scripts/locustfile.py | 18 ++- 4 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/ec2_init.sh diff --git a/.github/workflows/ec2_init.sh b/.github/workflows/ec2_init.sh new file mode 100644 index 0000000..6ddd6d1 --- /dev/null +++ b/.github/workflows/ec2_init.sh @@ -0,0 +1,139 @@ +#!/bin/bash +set -e +exec > /var/log/user-data.log 2>&1 + +# Boot up prechecks +echo "[1/8] Updating system packages..." +dnf update -y +dnf install -y unzip + +# Install Dependencies +echo "[2/8] Installing .NET 9 ASP.NET Core Runtime..." +dnf install -y libicu +curl -Lo /tmp/dotnet-install.sh https://dot.net/v1/dotnet-install.sh +chmod +x /tmp/dotnet-install.sh +/tmp/dotnet-install.sh --channel 9.0 --runtime aspnetcore --install-dir /usr/share/dotnet +ln -sf /usr/share/dotnet/dotnet /usr/local/bin/dotnet +echo "dotnet version: $(dotnet --version)" + +# Configure instance +echo "[3/8] Creating app user and directories..." +useradd -r -s /sbin/nologin culinarycommand || true +mkdir -p /opt/culinarycommand/app +chown culinarycommand:culinarycommand /opt/culinarycommand + +# Fetch app +echo "[4/8] Pulling app binaries from S3..." +aws s3 cp s3://culinary-command-s3-bucket/releases/latest/app.zip /tmp/app.zip +unzip -o /tmp/app.zip -d /opt/culinarycommand/app +chown -R culinarycommand:culinarycommand /opt/culinarycommand/app +rm -f /tmp/app.zip + +# Get secrets from AWS +echo "[5/8] Fetching secrets from SSM Parameter Store..." +DB_CONN=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/ConnectionStrings__DefaultConnection" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +COGNITO_CLIENT_SECRET=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/Cognito__ClientSecret" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +COGNITO_CLIENT_ID=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/Cognito__ClientId" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +COGNITO_USER_POOL_ID=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/Cognito__UserPoolId" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +COGNITO_DOMAIN=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/Cognito__Domain" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +GOOGLE_API_KEY=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/GOOGLE_API_KEY" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +LOGODEV_PUBLISHABLE_KEY=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/LogoDev__PublishableKey" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +LOGODEV_SECRET_KEY=$(aws ssm get-parameter \ + --name "/culinarycommand/prod/LogoDev__SecretKey" \ + --with-decryption \ + --region us-east-2 \ + --query "Parameter.Value" \ + --output text) + +# Write environment variables to file +echo "[6/8] Writing environment file..." +cat > /etc/culinarycommand.env << EOF +ASPNETCORE_ENVIRONMENT=Production +ASPNETCORE_URLS=http://0.0.0.0:5000 +ConnectionStrings__DefaultConnection=${DB_CONN} +COGNITO_CLIENT_SECRET=${COGNITO_CLIENT_SECRET} +Authentication__Cognito__ClientId=${COGNITO_CLIENT_ID} +Authentication__Cognito__ClientSecret=${COGNITO_CLIENT_SECRET} +Authentication__Cognito__UserPoolId=${COGNITO_USER_POOL_ID} +Authentication__Cognito__Domain=${COGNITO_DOMAIN} +Authentication__Cognito__CallbackPath=/signin-oidc +Authentication__Cognito__SignedOutCallbackPath=/signout-callback-oidc +AWS__Region=us-east-2 +GOOGLE_API_KEY=${GOOGLE_API_KEY} +LogoDev__PublishableKey=${LOGODEV_PUBLISHABLE_KEY} +LogoDev__SecretKey=${LOGODEV_SECRET_KEY} +EOF +chmod 600 /etc/culinarycommand.env + +# Create systemd service to host app +echo "[7/8] Creating systemd service..." +cat > /etc/systemd/system/culinarycommand.service << 'EOF' +[Unit] +Description=Culinary Command Blazor App +After=network.target + +[Service] +WorkingDirectory=/opt/culinarycommand/app +ExecStart=/usr/local/bin/dotnet /opt/culinarycommand/app/CulinaryCommand.dll +Restart=always +RestartSec=10 +EnvironmentFile=/etc/culinarycommand.env +User=culinarycommand +Group=culinarycommand +StandardOutput=journal +StandardError=journal +SyslogIdentifier=culinarycommand + +[Install] +WantedBy=multi-user.target +EOF + +# Enable and start the app +echo "[8/8] Enabling and starting Culinary Command service..." +systemctl daemon-reload +systemctl enable culinarycommand +systemctl start culinarycommand + +echo "Culinary Command bootstrap complete." diff --git a/CulinaryCommandApp/CulinaryCommand.csproj b/CulinaryCommandApp/CulinaryCommand.csproj index ff42df0..2989c24 100644 --- a/CulinaryCommandApp/CulinaryCommand.csproj +++ b/CulinaryCommandApp/CulinaryCommand.csproj @@ -11,6 +11,7 @@ + diff --git a/CulinaryCommandApp/Program.cs b/CulinaryCommandApp/Program.cs index 59b9df5..6034558 100644 --- a/CulinaryCommandApp/Program.cs +++ b/CulinaryCommandApp/Program.cs @@ -171,6 +171,19 @@ builder.Services.AddScoped(); builder.Services.AddHttpClient(); +if (builder.Environment.IsDevelopment()) +{ + var dp = Path.Combine(builder.Environment.ContentRootPath, ".dpkeys"); + builder.Services.AddDataProtection() + .PersistKeysToFileSystem(new DirectoryInfo(dp)) + .SetApplicationName("CulinaryCommand"); +} +else +{ + builder.Services.AddDataProtection() + .PersistKeysToAWSSystemsManager("/culinarycommand/prod/DataProtection") + .SetApplicationName("CulinaryCommand"); +} builder.Services.Configure(o => { @@ -183,16 +196,6 @@ o.KnownProxies.Clear(); }); -var env = builder.Environment; - -if (builder.Environment.IsDevelopment()) -{ - var dp = Path.Combine(builder.Environment.ContentRootPath, ".dpkeys"); - builder.Services.AddDataProtection() - .PersistKeysToFileSystem(new DirectoryInfo(dp)) - .SetApplicationName("CulinaryCommand"); -} - // // ===================== // Build App diff --git a/scripts/locustfile.py b/scripts/locustfile.py index 470d209..95de423 100644 --- a/scripts/locustfile.py +++ b/scripts/locustfile.py @@ -8,6 +8,16 @@ load_dotenv() +# Fetch token once at startup and share across all simulated users +# to avoid Cognito rate-limiting (429) during user spawn +_shared_token: str | None = None + +def get_shared_token() -> str: + global _shared_token + if _shared_token is None: + _shared_token = get_cognito_token() + return _shared_token + def get_secret_hash(username): client_id = os.getenv("COGNITO_CLIENT_ID") client_secret = os.getenv("COGNITO_CLIENT_SECRET") @@ -17,7 +27,7 @@ def get_secret_hash(username): client_secret.encode("utf-8"), msg=message.encode("utf-8"), digestmod=hashlib.sha256 - ).digest() + ).digest() # type: ignore return base64.b64encode(dig).decode() def get_cognito_token(): @@ -35,10 +45,10 @@ def get_cognito_token(): return response["AuthenticationResult"]["IdToken"] class LocustLoadTesting(HttpUser): - wait_time = between(1, 3) + wait_time = between(0.5, 1) def on_start(self): - token = get_cognito_token() + token = get_shared_token() self.client.headers.update({ "Authorization": f"Bearer {token}" @@ -48,9 +58,11 @@ def on_start(self): def browse_recipes(self): self.client.get("/recipes", name="Browse Recipes") + @task(1) def view_recipe(self): recipe_id = 2 self.client.get(f"/recipes/view/{recipe_id}", name="View Recipe") + @task(1) def view_dashboard(self): self.client.get("/dashboard", name="View Dashboard") \ No newline at end of file From 1c516aa89eb761b24f168a4156a4ee516ed0f3d4 Mon Sep 17 00:00:00 2001 From: Kevin Tran Date: Thu, 12 Mar 2026 22:11:22 -0500 Subject: [PATCH 2/3] chore: remove deploy-lightsail for now --- .github/workflows/deploy.yml | 300 +++++++++++++++++------------------ 1 file changed, 150 insertions(+), 150 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4408646..79b4ccb 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -64,156 +64,156 @@ jobs: path: ${{ env.PUBLISH_DIR }} retention-days: 1 - deploy: - runs-on: ubuntu-latest - needs: build - env: - AWS_REGION: us-east-2 - AWS_ACCOUNT_NUMBER: ${{ vars.AWS_ACCOUNT_NUMBER }} - PROJECT_PATH: CulinaryCommandApp/CulinaryCommand.csproj - PUBLISH_DIR: ./publish - REMOTE_APP_DIR: /var/www/culinarycommand - SERVICE_NAME: culinarycommand - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Download publish artifacts - uses: actions/download-artifact@v4 - with: - name: publish-${{ github.sha }} - path: ${{ env.PUBLISH_DIR }} - - - name: Add host key - run: | - mkdir -p ~/.ssh - for i in {1..5}; do - if ssh-keyscan -H "${{ secrets.LIGHTSAIL_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null; then - echo "Host key added." - break - fi - echo "ssh-keyscan failed (attempt $i), retrying in 5s..." - sleep 5 - done - - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_NUMBER }}:role/culinary-command-iac-role - aws-region: ${{ env.AWS_REGION }} - - - name: Setup Terraform - uses: hashicorp/setup-terraform@v3 - - - name: Terraform Init - working-directory: terraform - env: - TF_IN_AUTOMATION: true - TF_INPUT: false - run: terraform init -input=false -no-color - - - name: Terraform Plan - working-directory: terraform - env: - TF_IN_AUTOMATION: true - TF_INPUT: false - TF_VAR_lightsail_instance_name: culinary-command - TF_VAR_blueprint_id: ubuntu_22_04 - TF_VAR_bundle_id: nano_2_0 - TF_VAR_key_pair_name: culinary-command-key - run: terraform plan -input=false -no-color -out tfplan - - - name: Terraform Apply - if: github.ref == 'refs/heads/main' - working-directory: terraform - env: - TF_IN_AUTOMATION: true - TF_INPUT: false - TF_VAR_lightsail_instance_name: culinary-command - TF_VAR_blueprint_id: ubuntu_22_04 - TF_VAR_bundle_id: nano_2_0 - TF_VAR_key_pair_name: culinary-command-key - run: terraform apply -input=false -auto-approve tfplan - - - name: Display output variables - working-directory: terraform - run: terraform output -no-color - - - name: Start SSH agent - uses: webfactory/ssh-agent@v0.9.0 - with: - ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - - - name: Upload artifacts to Lightsail instance - run: | - REMOTE_TMP="~/deploy/${{ github.sha }}" - ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST}} "mkdir -p $REMOTE_TMP" - rsync -az --delete --exclude='.env' "${{ env.PUBLISH_DIR }}/" "${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }}:$REMOTE_TMP/" - - - name: Construct environment variables - run: | - ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} << "REMOTE_EOF" - sudo mkdir -p /var/www/culinarycommand - sudo tee /var/www/culinarycommand/.env > /dev/null << EOF - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:5000 - ConnectionStrings__DefaultConnection="Server=${{ secrets.RDS_HOST }};Port=3306;Database=${{ secrets.RDS_DB_NAME }};Uid=${{ secrets.RDS_DB_USER }};Pwd=${{ secrets.RDS_DB_PASSWORD }};SslMode=Required;" - GOOGLE_API_KEY=${{ secrets.GOOGLE_API_KEY }} - COGNITO_CLIENT_SECRET=${{ secrets.COGNITO_CLIENT_SECRET }} - Authentication__Cognito__ClientId=${{ secrets.COGNITO_CLIENT_ID }} - Authentication__Cognito__ClientSecret=${{ secrets.COGNITO_CLIENT_SECRET }} - Authentication__Cognito__Domain=${{ secrets.COGNITO_DOMAIN }} - Authentication__Cognito__UserPoolId=${{ secrets.COGNITO_USER_POOL_ID }} - AWS__Region=${{ env.AWS_REGION }} - LogoDev__PublishableKey=${{ secrets.LOGODEV_PUBLISHABLE_KEY }} - LogoDev__SecretKey=${{ secrets.LOGODEV_SECRET_KEY }} - EOF - sudo chown ${{ secrets.LIGHTSAIL_USER }}:${{ secrets.LIGHTSAIL_USER }} /var/www/culinarycommand/.env - sudo chmod 640 /var/www/culinarycommand/.env - - sudo tee /var/www/culinarycommand/.env.export > /dev/null << EOF - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://0.0.0.0:5000 - export ConnectionStrings__DefaultConnection="Server=${{ secrets.RDS_HOST }};Port=3306;Database=${{ secrets.RDS_DB_NAME }};Uid=${{ secrets.RDS_DB_USER }};Pwd=${{ secrets.RDS_DB_PASSWORD }};SslMode=Required;" - export GOOGLE_API_KEY="${{ secrets.GOOGLE_API_KEY }}" - export COGNITO_CLIENT_SECRET="${{ secrets.COGNITO_CLIENT_SECRET }}" - export Authentication__Cognito__ClientId="${{ secrets.COGNITO_CLIENT_ID }}" - export Authentication__Cognito__ClientSecret="${{ secrets.COGNITO_CLIENT_SECRET }}" - export Authentication__Cognito__Domain="${{ secrets.COGNITO_DOMAIN }}" - export Authentication__Cognito__UserPoolId="${{ secrets.COGNITO_USER_POOL_ID }}" - export AWS__Region="${{ env.AWS_REGION }}" - export LogoDev__PublishableKey="${{ secrets.LOGODEV_PUBLISHABLE_KEY }}" - export LogoDev__SecretKey="${{ secrets.LOGODEV_SECRET_KEY }}" - EOF - sudo chown ${{ secrets.LIGHTSAIL_USER }}:${{ secrets.LIGHTSAIL_USER }} /var/www/culinarycommand/.env.export - sudo chmod 640 /var/www/culinarycommand/.env.export - REMOTE_EOF - - - name: RDS port check (via peering) - run: | - ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} "\ - command -v nc >/dev/null || (sudo apt-get update && sudo apt-get install -y netcat-openbsd); \ - nc -vz ${{ secrets.RDS_HOST }} 3306 || (echo 'RDS port is not reachable over peering' && exit 1)" - - - name: Run EF migrations bundle on Lightsail - run: | - ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} "\ - sudo systemctl stop '${{ env.SERVICE_NAME }}' || true && \ - cd \$HOME/deploy/${{ github.sha }} && \ - set -a && . /var/www/culinarycommand/.env.export && set +a && \ - command -v ./efbundle >/dev/null || chmod +x ./efbundle && \ - ./efbundle && \ - sudo systemctl start '${{ env.SERVICE_NAME }}' || true" - - - name: Activate release and restart service - run: | - ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} "\ - sudo mkdir -p '${{ env.REMOTE_APP_DIR }}' && \ - sudo rsync -a --delete --exclude='.env' ~/deploy/${{ github.sha }}/ '${{ env.REMOTE_APP_DIR }}'/ && \ - sudo chown -R www-data:www-data '${{ env.REMOTE_APP_DIR }}' && \ - rm -rf ~/deploy/${{ github.sha }} && \ - sudo systemctl restart '${{ env.SERVICE_NAME }}' && \ - sudo systemctl --no-pager --lines=5 status '${{ env.SERVICE_NAME }}' || true" + # deploy: + # runs-on: ubuntu-latest + # needs: build + # env: + # AWS_REGION: us-east-2 + # AWS_ACCOUNT_NUMBER: ${{ vars.AWS_ACCOUNT_NUMBER }} + # PROJECT_PATH: CulinaryCommandApp/CulinaryCommand.csproj + # PUBLISH_DIR: ./publish + # REMOTE_APP_DIR: /var/www/culinarycommand + # SERVICE_NAME: culinarycommand + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + + # - name: Download publish artifacts + # uses: actions/download-artifact@v4 + # with: + # name: publish-${{ github.sha }} + # path: ${{ env.PUBLISH_DIR }} + + # - name: Add host key + # run: | + # mkdir -p ~/.ssh + # for i in {1..5}; do + # if ssh-keyscan -H "${{ secrets.LIGHTSAIL_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null; then + # echo "Host key added." + # break + # fi + # echo "ssh-keyscan failed (attempt $i), retrying in 5s..." + # sleep 5 + # done + + # - name: Configure AWS credentials + # uses: aws-actions/configure-aws-credentials@v4 + # with: + # role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_NUMBER }}:role/culinary-command-iac-role + # aws-region: ${{ env.AWS_REGION }} + + # - name: Setup Terraform + # uses: hashicorp/setup-terraform@v3 + + # - name: Terraform Init + # working-directory: terraform + # env: + # TF_IN_AUTOMATION: true + # TF_INPUT: false + # run: terraform init -input=false -no-color + + # - name: Terraform Plan + # working-directory: terraform + # env: + # TF_IN_AUTOMATION: true + # TF_INPUT: false + # TF_VAR_lightsail_instance_name: culinary-command + # TF_VAR_blueprint_id: ubuntu_22_04 + # TF_VAR_bundle_id: nano_2_0 + # TF_VAR_key_pair_name: culinary-command-key + # run: terraform plan -input=false -no-color -out tfplan + + # - name: Terraform Apply + # if: github.ref == 'refs/heads/main' + # working-directory: terraform + # env: + # TF_IN_AUTOMATION: true + # TF_INPUT: false + # TF_VAR_lightsail_instance_name: culinary-command + # TF_VAR_blueprint_id: ubuntu_22_04 + # TF_VAR_bundle_id: nano_2_0 + # TF_VAR_key_pair_name: culinary-command-key + # run: terraform apply -input=false -auto-approve tfplan + + # - name: Display output variables + # working-directory: terraform + # run: terraform output -no-color + + # - name: Start SSH agent + # uses: webfactory/ssh-agent@v0.9.0 + # with: + # ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + + # - name: Upload artifacts to Lightsail instance + # run: | + # REMOTE_TMP="~/deploy/${{ github.sha }}" + # ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST}} "mkdir -p $REMOTE_TMP" + # rsync -az --delete --exclude='.env' "${{ env.PUBLISH_DIR }}/" "${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }}:$REMOTE_TMP/" + + # - name: Construct environment variables + # run: | + # ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} << "REMOTE_EOF" + # sudo mkdir -p /var/www/culinarycommand + # sudo tee /var/www/culinarycommand/.env > /dev/null << EOF + # ASPNETCORE_ENVIRONMENT=Production + # ASPNETCORE_URLS=http://0.0.0.0:5000 + # ConnectionStrings__DefaultConnection="Server=${{ secrets.RDS_HOST }};Port=3306;Database=${{ secrets.RDS_DB_NAME }};Uid=${{ secrets.RDS_DB_USER }};Pwd=${{ secrets.RDS_DB_PASSWORD }};SslMode=Required;" + # GOOGLE_API_KEY=${{ secrets.GOOGLE_API_KEY }} + # COGNITO_CLIENT_SECRET=${{ secrets.COGNITO_CLIENT_SECRET }} + # Authentication__Cognito__ClientId=${{ secrets.COGNITO_CLIENT_ID }} + # Authentication__Cognito__ClientSecret=${{ secrets.COGNITO_CLIENT_SECRET }} + # Authentication__Cognito__Domain=${{ secrets.COGNITO_DOMAIN }} + # Authentication__Cognito__UserPoolId=${{ secrets.COGNITO_USER_POOL_ID }} + # AWS__Region=${{ env.AWS_REGION }} + # LogoDev__PublishableKey=${{ secrets.LOGODEV_PUBLISHABLE_KEY }} + # LogoDev__SecretKey=${{ secrets.LOGODEV_SECRET_KEY }} + # EOF + # sudo chown ${{ secrets.LIGHTSAIL_USER }}:${{ secrets.LIGHTSAIL_USER }} /var/www/culinarycommand/.env + # sudo chmod 640 /var/www/culinarycommand/.env + + # sudo tee /var/www/culinarycommand/.env.export > /dev/null << EOF + # ASPNETCORE_ENVIRONMENT=Production + # ASPNETCORE_URLS=http://0.0.0.0:5000 + # export ConnectionStrings__DefaultConnection="Server=${{ secrets.RDS_HOST }};Port=3306;Database=${{ secrets.RDS_DB_NAME }};Uid=${{ secrets.RDS_DB_USER }};Pwd=${{ secrets.RDS_DB_PASSWORD }};SslMode=Required;" + # export GOOGLE_API_KEY="${{ secrets.GOOGLE_API_KEY }}" + # export COGNITO_CLIENT_SECRET="${{ secrets.COGNITO_CLIENT_SECRET }}" + # export Authentication__Cognito__ClientId="${{ secrets.COGNITO_CLIENT_ID }}" + # export Authentication__Cognito__ClientSecret="${{ secrets.COGNITO_CLIENT_SECRET }}" + # export Authentication__Cognito__Domain="${{ secrets.COGNITO_DOMAIN }}" + # export Authentication__Cognito__UserPoolId="${{ secrets.COGNITO_USER_POOL_ID }}" + # export AWS__Region="${{ env.AWS_REGION }}" + # export LogoDev__PublishableKey="${{ secrets.LOGODEV_PUBLISHABLE_KEY }}" + # export LogoDev__SecretKey="${{ secrets.LOGODEV_SECRET_KEY }}" + # EOF + # sudo chown ${{ secrets.LIGHTSAIL_USER }}:${{ secrets.LIGHTSAIL_USER }} /var/www/culinarycommand/.env.export + # sudo chmod 640 /var/www/culinarycommand/.env.export + # REMOTE_EOF + + # - name: RDS port check (via peering) + # run: | + # ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} "\ + # command -v nc >/dev/null || (sudo apt-get update && sudo apt-get install -y netcat-openbsd); \ + # nc -vz ${{ secrets.RDS_HOST }} 3306 || (echo 'RDS port is not reachable over peering' && exit 1)" + + # - name: Run EF migrations bundle on Lightsail + # run: | + # ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} "\ + # sudo systemctl stop '${{ env.SERVICE_NAME }}' || true && \ + # cd \$HOME/deploy/${{ github.sha }} && \ + # set -a && . /var/www/culinarycommand/.env.export && set +a && \ + # command -v ./efbundle >/dev/null || chmod +x ./efbundle && \ + # ./efbundle && \ + # sudo systemctl start '${{ env.SERVICE_NAME }}' || true" + + # - name: Activate release and restart service + # run: | + # ssh ${{ secrets.LIGHTSAIL_USER }}@${{ secrets.LIGHTSAIL_HOST }} "\ + # sudo mkdir -p '${{ env.REMOTE_APP_DIR }}' && \ + # sudo rsync -a --delete --exclude='.env' ~/deploy/${{ github.sha }}/ '${{ env.REMOTE_APP_DIR }}'/ && \ + # sudo chown -R www-data:www-data '${{ env.REMOTE_APP_DIR }}' && \ + # rm -rf ~/deploy/${{ github.sha }} && \ + # sudo systemctl restart '${{ env.SERVICE_NAME }}' && \ + # sudo systemctl --no-pager --lines=5 status '${{ env.SERVICE_NAME }}' || true" deploy-autoscaling-group: runs-on: ubuntu-latest needs: build From bc76022db2fd2bc5209111f919393efab795a750 Mon Sep 17 00:00:00 2001 From: Kevin Tran Date: Thu, 12 Mar 2026 22:12:21 -0500 Subject: [PATCH 3/3] chore: uncomment ASG refresh --- .github/workflows/deploy.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 79b4ccb..e469772 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -247,9 +247,9 @@ jobs: aws s3 cp culinarycommand-${{ github.sha }}.zip \ s3://${{ env.S3_BUCKET }}/releases/latest/app.zip - # - name: Trigger ASG instance refresh - # run: | - # aws autoscaling start-instance-refresh \ - # --auto-scaling-group-name culinary-command-asg \ - # --preferences '{"MinHealthyPercentage": 50, "InstanceWarmup": 120}' \ - # --region ${{ env.AWS_REGION }} + - name: Trigger ASG instance refresh + run: | + aws autoscaling start-instance-refresh \ + --auto-scaling-group-name culinary-command-asg \ + --preferences '{"MinHealthyPercentage": 50, "InstanceWarmup": 120}' \ + --region ${{ env.AWS_REGION }}