Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Autodetect text files and forces unix eols, so Windows does not break them
* text=auto eol=lf

# Force images/fonts to be handled as binaries
*.jpg binary
*.jpeg binary
*.gif binary
*.png binary
126 changes: 101 additions & 25 deletions .github/scripts/pause.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/bin/bash
# This script pauses AWS resources (ECS service and RDS Aurora cluster) in the current AWS account.
# Made idempotent - safe to run multiple times, checks resource existence before acting.

set -e # Exit on error
set -euo pipefail # Exit on error, undefined variables, and pipe failures
Copy link
Preview

Copilot AI Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Similar to the resume script, this uses set -euo pipefail but frequently toggles error handling with set +e. Consider using || true or command-specific error handling instead of repeatedly changing the global error handling behavior.

Copilot uses AI. Check for mistakes.


# Error handler function
function error_handler() {
Expand Down Expand Up @@ -31,8 +32,12 @@ function validate_args() {
# Check if Aurora DB cluster exists and get its status
function check_aurora_cluster() {
local cluster_id="${STACK_PREFIX}-aurora-${ENVIRONMENT}"
local status=$(aws rds describe-db-clusters --db-cluster-identifier "$cluster_id" \
--query 'DBClusters[0].Status' --output text 2>/dev/null || echo "false")

# Use || true to handle expected failures gracefully
local status
status=$(aws rds describe-db-clusters --db-cluster-identifier "$cluster_id" \
--query 'DBClusters[0].Status' --output text 2>/dev/null || echo "not-found")

echo "$status"
}

Expand All @@ -41,23 +46,63 @@ function pause_aurora_cluster() {
local cluster_id="${STACK_PREFIX}-aurora-${ENVIRONMENT}"
local status=$1

if [ "$status" = "false" ]; then
echo "Skipping Aurora pause operation: DB cluster does not exist"
return
echo "Aurora cluster status: ${status}"

if [ "$status" = "not-found" ]; then
echo "Aurora cluster does not exist - skipping pause operation"
return 0
elif [ "$status" = "available" ]; then
echo "Pausing Aurora cluster: $cluster_id"
aws rds stop-db-cluster --db-cluster-identifier "$cluster_id" --no-cli-pager --output json

# Use if/then structure for better error handling
if ! aws rds stop-db-cluster --db-cluster-identifier "$cluster_id" --no-cli-pager --output json; then
echo "Failed to pause Aurora cluster: $cluster_id"
return 1
else
echo "Aurora cluster pause initiated successfully"
fi
elif [ "$status" = "stopped" ]; then
echo "Aurora cluster is already stopped - no action needed"
elif [ "$status" = "stopping" ]; then
echo "Aurora cluster is already stopping - no action needed"
else
echo "DB cluster is not in an available state. Current state: $status"
echo "Aurora cluster is in state: $status - no action taken"
fi

return 0
}

# Check if ECS cluster exists
function check_ecs_cluster() {
local cluster_name="${STACK_PREFIX}-node-api-${ENVIRONMENT}"
local status=$(aws ecs describe-clusters --clusters "$cluster_name" \
--query 'clusters[0].status' --output text 2>/dev/null || echo "INACTIVE")
echo "$status"

# Use || true to handle expected failures gracefully
local status
status=$(aws ecs describe-clusters --clusters "$cluster_name" \
--query 'clusters[0].status' --output text 2>/dev/null || echo "not-found")

if [ "$status" = "None" ] || [ -z "$status" ]; then
echo "not-found"
else
echo "$status"
fi
}

# Check if ECS service exists
function check_ecs_service() {
local cluster_name="${STACK_PREFIX}-node-api-${ENVIRONMENT}"
local service_name="${STACK_PREFIX}-node-api-${ENVIRONMENT}"

# Use || true to handle expected failures gracefully
local status
status=$(aws ecs describe-services --cluster "$cluster_name" --services "$service_name" \
--query 'services[0].status' --output text 2>/dev/null || echo "not-found")

if [ "$status" = "None" ] || [ -z "$status" ]; then
echo "not-found"
else
echo "$status"
fi
}

# Pause ECS service by setting min/max capacity to 0
Expand All @@ -66,42 +111,73 @@ function pause_ecs_service() {
local service_name="${STACK_PREFIX}-node-api-${ENVIRONMENT}"
local cluster_status=$1

echo "ECS cluster status: ${cluster_status}"

if [ "$cluster_status" = "not-found" ]; then
echo "ECS cluster $cluster_name does not exist - skipping pause operation"
return 0
fi

if [ "$cluster_status" != "ACTIVE" ]; then
echo "Skipping ECS pause operation: Cluster $cluster_name does not exist"
return
echo "ECS cluster $cluster_name is not active (status: ${cluster_status}) - skipping pause operation"
return 0
fi

local service_status=$(aws ecs describe-services --cluster "$cluster_name" --services "$service_name" \
--query 'services[0].status' --output text 2>/dev/null || echo "INACTIVE")
local service_status=$(check_ecs_service)
echo "ECS service status: ${service_status}"

if [ "$service_status" = "not-found" ]; then
echo "ECS service $service_name does not exist in cluster $cluster_name - skipping pause operation"
return 0
fi

if [ "$service_status" = "ACTIVE" ]; then
echo "Scaling down ECS service: $service_name"
aws application-autoscaling register-scalable-target \

# Use if/then structure for better error handling
if ! aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id "service/$cluster_name/$service_name" \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 0 \
--max-capacity 0 \
--no-cli-pager \
--output json
--output json; then
echo "Failed to scale down ECS service: $service_name"
return 1
else
echo "ECS service scaled down successfully"
fi
elif [ "$service_status" = "DRAINING" ]; then
echo "ECS service is already draining - no action needed"
else
echo "ECS service $service_name does not exist in cluster $cluster_name"
echo "ECS service is in state: $service_status - no action taken"
fi

return 0
}

# Main execution
validate_args

echo "Starting pause operations for environment: ${ENVIRONMENT} with stack prefix: ${STACK_PREFIX}"

# Check and pause Aurora cluster
aurora_status=$(check_aurora_cluster)
[ "$aurora_status" = "false" ] || echo "Aurora cluster status: $aurora_status"
if pause_aurora_cluster "$aurora_status"; then
echo "Aurora cluster operations completed successfully"
else
echo "Aurora cluster operations failed"
exit 1
fi

# Check and pause ECS service
ecs_status=$(check_ecs_cluster)
[ "$ecs_status" = "INACTIVE" ] || echo "ECS cluster status: $ecs_status"

# Perform pause operations
pause_ecs_service "$ecs_status"
pause_aurora_cluster "$aurora_status"
if pause_ecs_service "$ecs_status"; then
echo "ECS service operations completed successfully"
else
echo "ECS service operations failed"
exit 1
fi

echo "Pause operations completed"
echo "All pause operations completed successfully"
127 changes: 100 additions & 27 deletions .github/scripts/resume.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/bin/bash
# This script resumes AWS resources (ECS service and RDS Aurora cluster) in the specified AWS account.
# Made idempotent - safe to run multiple times, checks resource existence before acting.

set -e # Exit on error
set -euo pipefail # Exit on error, undefined variables, and pipe failures
Copy link
Preview

Copilot AI Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The script uses set -euo pipefail but then frequently disables error exit with set +e throughout the script. Consider using a more targeted approach like || true for specific commands that are expected to potentially fail, rather than toggling the error handling mode repeatedly.

Copilot uses AI. Check for mistakes.


# Error handling function
error_handler() {
Expand All @@ -11,7 +12,7 @@ error_handler() {
exit 1
}

# Set trap for error handling
# Set trap for error handling (but not for resource not found errors)
trap 'error_handler ${LINENO} ${FUNCNAME[0]}' ERR

# Function to check if required parameters are provided
Expand All @@ -31,7 +32,11 @@ check_db_cluster() {
local prefix=$1
local env=$2
local cluster_id="${prefix}-aurora-${env}"
local status=$(aws rds describe-db-clusters --db-cluster-identifier ${cluster_id} --query 'DBClusters[0].Status' --output text 2>/dev/null || echo "not-found")

# Use || true to handle expected failures gracefully
local status
status=$(aws rds describe-db-clusters --db-cluster-identifier "${cluster_id}" --query 'DBClusters[0].Status' --output text 2>/dev/null || echo "not-found")

echo "$status"
}

Expand All @@ -42,56 +47,109 @@ start_db_cluster() {
local cluster_id="${prefix}-aurora-${env}"

echo "Starting DB cluster ${cluster_id}..."
aws rds start-db-cluster --db-cluster-identifier ${cluster_id} --no-cli-pager --output json

# Start the cluster and capture result
if ! aws rds start-db-cluster --db-cluster-identifier "${cluster_id}" --no-cli-pager --output json; then
echo "Failed to start DB cluster ${cluster_id}"
return 1
fi

echo "Waiting for DB cluster to be available..."
if ! aws rds wait db-cluster-available --db-cluster-identifier ${cluster_id}; then
echo "Timeout waiting for DB cluster to become available"
if ! aws rds wait db-cluster-available --db-cluster-identifier "${cluster_id}"; then
echo "Timeout or error waiting for DB cluster to become available"
return 1
fi

echo "DB cluster is now available"
return 0
}

# Function to check if ECS cluster exists
check_ecs_cluster() {
local cluster=$1

# Use || true to handle expected failures gracefully
local status
status=$(aws ecs describe-clusters --clusters "${cluster}" --query 'clusters[0].status' --output text 2>/dev/null || echo "not-found")

if [ "$status" = "None" ] || [ -z "$status" ]; then
echo "not-found"
else
echo "$status"
fi
}

# Function to check if ECS service exists
check_ecs_service() {
local cluster=$1
local service=$2

# Use || true to handle expected failures gracefully
local status
status=$(aws ecs describe-services --cluster "${cluster}" --services "${service}" --query 'services[0].status' --output text 2>/dev/null || echo "not-found")

if [ "$status" = "None" ] || [ -z "$status" ]; then
echo "not-found"
else
echo "$status"
fi
}

# Function to resume ECS service
resume_ecs_service() {
local prefix=$1
local env=$2
local cluster="${prefix}-node-api-${env}"
local service="${prefix}-node-api-${env}"

echo "Resuming ECS service ${service} on cluster ${cluster}..."
# Check if the ECS cluster exists
if ! aws ecs describe-clusters --clusters "${cluster}" --query 'clusters[0]' --output text &>/dev/null; then
echo "Checking ECS cluster ${cluster}..."
local cluster_status=$(check_ecs_cluster "${cluster}")

if [ "$cluster_status" = "not-found" ]; then
echo "ECS cluster ${cluster} does not exist. Skipping service resume."
return 0
fi

if [ "$cluster_status" != "ACTIVE" ]; then
echo "ECS cluster ${cluster} is not active (status: ${cluster_status}). Skipping service resume."
return 0
fi

# Check if the ECS service exists
if ! aws ecs describe-services --cluster "${cluster}" --services "${service}" --query 'services[0]' --output text &>/dev/null; then
echo "Checking ECS service ${service}..."
local service_status=$(check_ecs_service "${cluster}" "${service}")

if [ "$service_status" = "not-found" ]; then
echo "ECS service ${service} does not exist in cluster ${cluster}. Skipping service resume."
return 0
fi
# Update scaling policy
aws application-autoscaling register-scalable-target \

echo "Resuming ECS service ${service} on cluster ${cluster}..."

# Update scaling policy - use || true to handle potential failures
if ! aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/${cluster}/${service} \
--resource-id "service/${cluster}/${service}" \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 1 \
--max-capacity 2 \
--no-cli-pager \
--output json
--output json; then
echo "Warning: Failed to update scaling policy for ECS service ${service}"
fi

# Update service desired count
aws ecs update-service \
--cluster ${cluster} \
--service ${service} \
if ! aws ecs update-service \
--cluster "${cluster}" \
--service "${service}" \
--desired-count 1 \
--no-cli-pager \
--output json
--output json; then
echo "Failed to update ECS service ${service} desired count"
return 1
fi

echo "ECS service has been resumed"
return 0
}

# Main function
Expand All @@ -103,20 +161,35 @@ main() {

# Check DB cluster status
local db_status=$(check_db_cluster "$prefix" "$env")
echo "DB cluster status: ${db_status}"

if [ "$db_status" == "not-found" ]; then
echo "Skipping resume operation, DB cluster does not exist"
return 0
elif [ "$db_status" == "stopped" ]; then
start_db_cluster "$prefix" "$env" || return 1
if [ "$db_status" = "not-found" ]; then
echo "DB cluster does not exist - skipping DB operations"
elif [ "$db_status" = "stopped" ]; then
echo "DB cluster is stopped - starting it..."
if start_db_cluster "$prefix" "$env"; then
echo "DB cluster started successfully"
else
echo "Failed to start DB cluster"
return 1
fi
elif [ "$db_status" = "available" ]; then
echo "DB cluster is already available - no action needed"
elif [ "$db_status" = "starting" ]; then
echo "DB cluster is already starting - no action needed"
else
echo "DB cluster is not in a stopped state. Current state: $db_status"
echo "DB cluster is in state: $db_status - no action taken"
fi

# Resume ECS service
resume_ecs_service "$prefix" "$env"
if resume_ecs_service "$prefix" "$env"; then
echo "ECS service operations completed successfully"
else
echo "ECS service operations failed"
return 1
fi

echo "Resources have been resumed successfully"
echo "Resources resume operations completed successfully"
}

# Parse and check arguments
Expand Down
Loading
Loading