shoehorning graphql, step functions and lamdas. aws deployment scripts
This commit is contained in:
317
ctrl/deploy.sh
317
ctrl/deploy.sh
@@ -1,18 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Deploy MPR to remote server via rsync
|
||||
# Uses project .gitignore for excludes
|
||||
# MPR Deploy Script
|
||||
#
|
||||
# Usage: ./ctrl/deploy.sh [--restart] [--dry-run]
|
||||
# Usage: ./ctrl/deploy.sh <command> [options]
|
||||
#
|
||||
# Examples:
|
||||
# ./ctrl/deploy.sh # Sync files only
|
||||
# ./ctrl/deploy.sh --restart # Sync and restart services
|
||||
# ./ctrl/deploy.sh --dry-run # Preview sync
|
||||
# Commands:
|
||||
# rsync [--restart] [--dry-run] Sync to remote server via rsync
|
||||
# aws Deploy AWS infrastructure (Lambda, Step Functions, S3)
|
||||
|
||||
set -e
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
source "$SCRIPT_DIR/.env" 2>/dev/null || true
|
||||
|
||||
@@ -21,56 +20,268 @@ GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
if [ -z "$SERVER" ] || [ -z "$REMOTE_PATH" ]; then
|
||||
echo -e "${RED}Error: SERVER and REMOTE_PATH must be set in ctrl/.env${NC}"
|
||||
echo "Example:"
|
||||
echo " SERVER=user@host"
|
||||
echo " REMOTE_PATH=~/mpr"
|
||||
exit 1
|
||||
fi
|
||||
# ─── Rsync Deploy ─────────────────────────────────────────────────────────────
|
||||
|
||||
RESTART=false
|
||||
DRY_RUN=""
|
||||
deploy_rsync() {
|
||||
if [ -z "${SERVER:-}" ] || [ -z "${REMOTE_PATH:-}" ]; then
|
||||
echo -e "${RED}Error: SERVER and REMOTE_PATH must be set in ctrl/.env${NC}"
|
||||
echo "Example:"
|
||||
echo " SERVER=user@host"
|
||||
echo " REMOTE_PATH=~/mpr"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--restart)
|
||||
RESTART=true
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN="--dry-run"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
RESTART=false
|
||||
DRY_RUN=""
|
||||
|
||||
echo -e "${GREEN}=== Deploying MPR to $SERVER:$REMOTE_PATH ===${NC}"
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--restart) RESTART=true; shift ;;
|
||||
--dry-run) DRY_RUN="--dry-run"; shift ;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Sync files using .gitignore for excludes
|
||||
echo -e "${YELLOW}Syncing files...${NC}"
|
||||
rsync -avz --delete $DRY_RUN \
|
||||
--filter=':- .gitignore' \
|
||||
--exclude='.git' \
|
||||
--exclude='media/*' \
|
||||
--exclude='ctrl/.env' \
|
||||
"$PROJECT_ROOT/" "$SERVER:$REMOTE_PATH/"
|
||||
echo -e "${GREEN}=== Deploying MPR to $SERVER:$REMOTE_PATH ===${NC}"
|
||||
|
||||
if [ -n "$DRY_RUN" ]; then
|
||||
echo -e "${YELLOW}Dry run - no changes made${NC}"
|
||||
exit 0
|
||||
fi
|
||||
echo -e "${YELLOW}Syncing files...${NC}"
|
||||
rsync -avz --delete $DRY_RUN \
|
||||
--filter=':- .gitignore' \
|
||||
--exclude='.git' \
|
||||
--exclude='media/*' \
|
||||
--exclude='ctrl/.env' \
|
||||
"$PROJECT_ROOT/" "$SERVER:$REMOTE_PATH/"
|
||||
|
||||
# Copy env template if .env doesn't exist on remote
|
||||
ssh "$SERVER" "[ -f $REMOTE_PATH/ctrl/.env ] || cp $REMOTE_PATH/ctrl/.env.template $REMOTE_PATH/ctrl/.env"
|
||||
if [ -n "$DRY_RUN" ]; then
|
||||
echo -e "${YELLOW}Dry run - no changes made${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$RESTART" = true ]; then
|
||||
echo -e "${YELLOW}Restarting services...${NC}"
|
||||
ssh "$SERVER" "cd $REMOTE_PATH/ctrl && docker compose down && docker compose up -d --build"
|
||||
fi
|
||||
ssh "$SERVER" "[ -f $REMOTE_PATH/ctrl/.env ] || cp $REMOTE_PATH/ctrl/.env.template $REMOTE_PATH/ctrl/.env"
|
||||
|
||||
echo -e "${GREEN}Done!${NC}"
|
||||
if [ "$RESTART" = true ]; then
|
||||
echo -e "${YELLOW}Restarting services...${NC}"
|
||||
ssh "$SERVER" "cd $REMOTE_PATH/ctrl && docker compose down && docker compose up -d --build"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Done!${NC}"
|
||||
}
|
||||
|
||||
# ─── AWS Deploy ────────────────────────────────────────────────────────────────
|
||||
|
||||
deploy_aws() {
|
||||
REGION="${AWS_REGION:-us-east-1}"
|
||||
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
|
||||
PROJECT="mpr"
|
||||
|
||||
# S3
|
||||
BUCKET_IN="${S3_BUCKET_IN:-mpr-media-in}"
|
||||
BUCKET_OUT="${S3_BUCKET_OUT:-mpr-media-out}"
|
||||
|
||||
# ECR
|
||||
ECR_REPO="${PROJECT}-transcode"
|
||||
ECR_URI="${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${ECR_REPO}"
|
||||
|
||||
# Lambda
|
||||
LAMBDA_NAME="${PROJECT}-transcode"
|
||||
LAMBDA_TIMEOUT=900
|
||||
LAMBDA_MEMORY=2048
|
||||
|
||||
# Step Functions
|
||||
SFN_NAME="${PROJECT}-transcode"
|
||||
|
||||
# IAM
|
||||
LAMBDA_ROLE_NAME="${PROJECT}-lambda-role"
|
||||
SFN_ROLE_NAME="${PROJECT}-sfn-role"
|
||||
|
||||
# Callback
|
||||
CALLBACK_URL="${CALLBACK_URL:-https://mpr.mcrn.ar/api}"
|
||||
CALLBACK_API_KEY="${CALLBACK_API_KEY:-changeme}"
|
||||
|
||||
echo -e "${GREEN}=== Deploying MPR to AWS ($REGION, account $ACCOUNT_ID) ===${NC}"
|
||||
|
||||
# ─── S3 Buckets ───────────────────────────────────────────────────────
|
||||
|
||||
echo -e "${YELLOW}Creating S3 buckets...${NC}"
|
||||
for bucket in "$BUCKET_IN" "$BUCKET_OUT"; do
|
||||
if ! aws s3api head-bucket --bucket "$bucket" 2>/dev/null; then
|
||||
aws s3api create-bucket \
|
||||
--bucket "$bucket" \
|
||||
--region "$REGION" \
|
||||
--create-bucket-configuration LocationConstraint="$REGION"
|
||||
echo " Created $bucket"
|
||||
else
|
||||
echo " $bucket already exists"
|
||||
fi
|
||||
done
|
||||
|
||||
# ─── IAM Roles ────────────────────────────────────────────────────────
|
||||
|
||||
echo -e "${YELLOW}Creating IAM roles...${NC}"
|
||||
|
||||
if ! aws iam get-role --role-name "$LAMBDA_ROLE_NAME" 2>/dev/null; then
|
||||
aws iam create-role \
|
||||
--role-name "$LAMBDA_ROLE_NAME" \
|
||||
--assume-role-policy-document '{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "lambda.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}]
|
||||
}'
|
||||
aws iam attach-role-policy \
|
||||
--role-name "$LAMBDA_ROLE_NAME" \
|
||||
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
|
||||
aws iam put-role-policy \
|
||||
--role-name "$LAMBDA_ROLE_NAME" \
|
||||
--policy-name "${PROJECT}-s3-access" \
|
||||
--policy-document '{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Action": ["s3:GetObject", "s3:PutObject"],
|
||||
"Resource": [
|
||||
"arn:aws:s3:::'"$BUCKET_IN"'/*",
|
||||
"arn:aws:s3:::'"$BUCKET_OUT"'/*"
|
||||
]
|
||||
}]
|
||||
}'
|
||||
echo " Created $LAMBDA_ROLE_NAME"
|
||||
echo " Waiting for role to propagate..."
|
||||
sleep 10
|
||||
else
|
||||
echo " $LAMBDA_ROLE_NAME already exists"
|
||||
fi
|
||||
LAMBDA_ROLE_ARN=$(aws iam get-role --role-name "$LAMBDA_ROLE_NAME" --query Role.Arn --output text)
|
||||
|
||||
if ! aws iam get-role --role-name "$SFN_ROLE_NAME" 2>/dev/null; then
|
||||
aws iam create-role \
|
||||
--role-name "$SFN_ROLE_NAME" \
|
||||
--assume-role-policy-document '{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": "states.amazonaws.com"},
|
||||
"Action": "sts:AssumeRole"
|
||||
}]
|
||||
}'
|
||||
aws iam put-role-policy \
|
||||
--role-name "$SFN_ROLE_NAME" \
|
||||
--policy-name "${PROJECT}-sfn-invoke-lambda" \
|
||||
--policy-document '{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [{
|
||||
"Effect": "Allow",
|
||||
"Action": "lambda:InvokeFunction",
|
||||
"Resource": "arn:aws:lambda:'"$REGION"':'"$ACCOUNT_ID"':function:'"$LAMBDA_NAME"'"
|
||||
}]
|
||||
}'
|
||||
echo " Created $SFN_ROLE_NAME"
|
||||
sleep 10
|
||||
else
|
||||
echo " $SFN_ROLE_NAME already exists"
|
||||
fi
|
||||
SFN_ROLE_ARN=$(aws iam get-role --role-name "$SFN_ROLE_NAME" --query Role.Arn --output text)
|
||||
|
||||
# ─── ECR Repository ──────────────────────────────────────────────────
|
||||
|
||||
echo -e "${YELLOW}Setting up ECR...${NC}"
|
||||
if ! aws ecr describe-repositories --repository-names "$ECR_REPO" --region "$REGION" 2>/dev/null; then
|
||||
aws ecr create-repository --repository-name "$ECR_REPO" --region "$REGION"
|
||||
echo " Created ECR repo $ECR_REPO"
|
||||
else
|
||||
echo " ECR repo $ECR_REPO already exists"
|
||||
fi
|
||||
|
||||
# ─── Build & Push Lambda Image ───────────────────────────────────────
|
||||
|
||||
echo -e "${YELLOW}Building Lambda container image...${NC}"
|
||||
|
||||
docker build -f ctrl/lambda/Dockerfile -t "${ECR_REPO}:latest" .
|
||||
|
||||
echo -e "${YELLOW}Pushing to ECR...${NC}"
|
||||
aws ecr get-login-password --region "$REGION" | \
|
||||
docker login --username AWS --password-stdin "${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com"
|
||||
|
||||
docker tag "${ECR_REPO}:latest" "${ECR_URI}:latest"
|
||||
docker push "${ECR_URI}:latest"
|
||||
|
||||
# ─── Lambda Function ─────────────────────────────────────────────────
|
||||
|
||||
echo -e "${YELLOW}Deploying Lambda function...${NC}"
|
||||
LAMBDA_ARN="arn:aws:lambda:${REGION}:${ACCOUNT_ID}:function:${LAMBDA_NAME}"
|
||||
|
||||
if aws lambda get-function --function-name "$LAMBDA_NAME" --region "$REGION" 2>/dev/null; then
|
||||
aws lambda update-function-code \
|
||||
--function-name "$LAMBDA_NAME" \
|
||||
--image-uri "${ECR_URI}:latest" \
|
||||
--region "$REGION"
|
||||
echo " Updated $LAMBDA_NAME"
|
||||
else
|
||||
aws lambda create-function \
|
||||
--function-name "$LAMBDA_NAME" \
|
||||
--package-type Image \
|
||||
--code ImageUri="${ECR_URI}:latest" \
|
||||
--role "$LAMBDA_ROLE_ARN" \
|
||||
--timeout "$LAMBDA_TIMEOUT" \
|
||||
--memory-size "$LAMBDA_MEMORY" \
|
||||
--environment "Variables={S3_BUCKET_IN=${BUCKET_IN},S3_BUCKET_OUT=${BUCKET_OUT},AWS_REGION=${REGION}}" \
|
||||
--region "$REGION"
|
||||
echo " Created $LAMBDA_NAME"
|
||||
fi
|
||||
|
||||
# ─── Step Functions ───────────────────────────────────────────────────
|
||||
|
||||
echo -e "${YELLOW}Deploying Step Functions state machine...${NC}"
|
||||
|
||||
SFN_DEFINITION=$(sed "s|\${TranscodeLambdaArn}|${LAMBDA_ARN}|g" ctrl/state-machine.json)
|
||||
|
||||
SFN_ARN="arn:aws:states:${REGION}:${ACCOUNT_ID}:stateMachine:${SFN_NAME}"
|
||||
if aws stepfunctions describe-state-machine --state-machine-arn "$SFN_ARN" --region "$REGION" 2>/dev/null; then
|
||||
aws stepfunctions update-state-machine \
|
||||
--state-machine-arn "$SFN_ARN" \
|
||||
--definition "$SFN_DEFINITION" \
|
||||
--region "$REGION"
|
||||
echo " Updated $SFN_NAME"
|
||||
else
|
||||
aws stepfunctions create-state-machine \
|
||||
--name "$SFN_NAME" \
|
||||
--definition "$SFN_DEFINITION" \
|
||||
--role-arn "$SFN_ROLE_ARN" \
|
||||
--region "$REGION"
|
||||
echo " Created $SFN_NAME"
|
||||
fi
|
||||
|
||||
# ─── Summary ──────────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Deployment complete!${NC}"
|
||||
echo ""
|
||||
echo "Add these to your .env:"
|
||||
echo " MPR_EXECUTOR=lambda"
|
||||
echo " STEP_FUNCTION_ARN=${SFN_ARN}"
|
||||
echo " LAMBDA_FUNCTION_ARN=${LAMBDA_ARN}"
|
||||
echo " S3_BUCKET_IN=${BUCKET_IN}"
|
||||
echo " S3_BUCKET_OUT=${BUCKET_OUT}"
|
||||
echo " CALLBACK_URL=${CALLBACK_URL}"
|
||||
echo " CALLBACK_API_KEY=${CALLBACK_API_KEY}"
|
||||
}
|
||||
|
||||
# ─── Main ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
COMMAND="${1:-}"
|
||||
shift || true
|
||||
|
||||
case "$COMMAND" in
|
||||
rsync) deploy_rsync "$@" ;;
|
||||
aws) deploy_aws "$@" ;;
|
||||
*)
|
||||
echo "Usage: ./ctrl/deploy.sh <command> [options]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " rsync [--restart] [--dry-run] Sync to remote server"
|
||||
echo " aws Deploy AWS infrastructure"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user