#!/bin/bash # MPR Deploy Script # # Usage: ./ctrl/deploy.sh [options] # # Commands: # rsync [--restart] [--dry-run] Sync to remote server via rsync # aws Deploy AWS infrastructure (Lambda, Step Functions, S3) 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 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # ─── Rsync Deploy ───────────────────────────────────────────────────────────── 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 RESTART=false DRY_RUN="" 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 echo -e "${GREEN}=== Deploying MPR to $SERVER:$REMOTE_PATH ===${NC}" 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/" if [ -n "$DRY_RUN" ]; then echo -e "${YELLOW}Dry run - no changes made${NC}" exit 0 fi ssh "$SERVER" "[ -f $REMOTE_PATH/ctrl/.env ] || cp $REMOTE_PATH/ctrl/.env.template $REMOTE_PATH/ctrl/.env" 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 [options]" echo "" echo "Commands:" echo " rsync [--restart] [--dry-run] Sync to remote server" echo " aws Deploy AWS infrastructure" exit 1 ;; esac