Files
mediaproc/ctrl/deploy.sh

288 lines
11 KiB
Bash
Executable File

#!/bin/bash
# MPR Deploy Script
#
# Usage: ./ctrl/deploy.sh <command> [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 <command> [options]"
echo ""
echo "Commands:"
echo " rsync [--restart] [--dry-run] Sync to remote server"
echo " aws Deploy AWS infrastructure"
exit 1
;;
esac